-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Anemometer functionality to be displayed on the dashboard #169
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from 'react'; | ||
import { addArgs, createStory } from 'utils/stories'; | ||
import { SensorDataT, SensorsT } from 'types/data'; | ||
import WMStatus, { WMStatusProps } from './WMStatus'; | ||
|
||
export default { | ||
component: WMStatus, | ||
title: 'components/v3/status/WirelessModuleStatus', | ||
}; | ||
|
||
const Template = addArgs<WMStatusProps>((props) => <WMStatus {...props} />); | ||
|
||
const sensorData = (type: string, value: SensorsT): SensorDataT => ({ | ||
type, | ||
value, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
import React from 'react'; | ||
import { Accordion, Button, Card, Col, Table } from 'react-bootstrap'; | ||
import OnlineStatusPill from 'components/common/OnlineStatusPill'; | ||
import { WMStatus as WMStatusT } from 'types/data'; | ||
import { isOnline, roundNum } from 'utils/data'; | ||
import { camelCaseToStartCase } from 'utils/string'; | ||
|
||
export type WMStatusProps = WMStatusT; | ||
|
||
export default function WMStatus(props: WMStatusProps) { | ||
const { moduleName, online } = props; | ||
|
||
const statusPill = ( | ||
<span> | ||
<b>{moduleName}</b> <OnlineStatusPill isOnline={online} /> | ||
</span> | ||
); | ||
|
||
function extractData(type: string, data: any) { | ||
interface strMap { | ||
[key: string]: string; | ||
} | ||
interface numMap2 { | ||
[key: string]: number; | ||
} | ||
|
||
const units: strMap = { | ||
speed: 'km/h', | ||
satellites: '', | ||
pdop: '', | ||
latitude: '°N', | ||
longitude: '°E', | ||
altitude: 'm', | ||
course: '°', | ||
datetime: '', | ||
temperature: '°C', | ||
humidity: '%', | ||
steeringAngle: '°', | ||
co2: 'ppm', | ||
power: 'W', | ||
cadence: 'rpm', | ||
heartRate: 'bpm', | ||
reedVelocity: 'km/h', | ||
reedDistance: 'km', | ||
antSpeed: 'km/h', | ||
antDistance: 'km', | ||
}; | ||
|
||
const decimals: numMap2 = { | ||
speed: 2, | ||
satellites: 0, | ||
pdop: 2, | ||
latitude: 5, | ||
longitude: 5, | ||
altitude: 1, | ||
course: 1, | ||
temperature: 1, | ||
humidity: 0, | ||
steeringAngle: 1, | ||
co2: 0, | ||
power: 0, | ||
cadence: 0, | ||
heartRate: 0, | ||
reedVelocity: 2, | ||
reedDistance: 2, | ||
antSpeed: 2, | ||
antDistance: 2, | ||
x: 2, | ||
y: 2, | ||
z: 2, | ||
}; | ||
|
||
/** | ||
* receives a value and its unit and format them appropriately | ||
* | ||
* @param name type's name | ||
* @param value type's value | ||
* @param unit the unit | ||
* @returns string containing the value and its unit | ||
*/ | ||
function formatValue(name: string, value: any, unit: any) { | ||
let displayValue; | ||
let val = value; | ||
if (val !== null && val !== undefined) { | ||
if (name === 'Date' || name === 'Time') { | ||
displayValue = | ||
name === 'Date' ? value.substring(0, 10) : value.substring(11, 19); | ||
} else { | ||
const dec = decimals[name]; | ||
if (unit === 'km') { | ||
val /= 1000; | ||
} else if (unit === 'km/h') { | ||
val *= 3.6; | ||
} | ||
displayValue = roundNum(val, dec); | ||
} | ||
} else { | ||
displayValue = '-'; | ||
} | ||
const displayUnit = unit ? ` ${unit}` : ''; | ||
|
||
return `${displayValue}${displayUnit}`; | ||
} | ||
|
||
let output = <></>; | ||
if (type === 'anemometer') { | ||
const anemRows: any[] = []; | ||
Object.entries(data).forEach((arr) => { | ||
anemRows.push({ name: arr[0], value: arr[1] }); | ||
}); | ||
output = ( | ||
<Table borderless> | ||
<tbody> | ||
{anemRows.map(({ name, value }) => ( | ||
<tr | ||
key={name} | ||
style={{ | ||
width: '150px', | ||
borderBottomWidth: 1, | ||
borderBottomColor: 'gray', | ||
borderBottomStyle: 'solid', | ||
}} | ||
> | ||
<td>{camelCaseToStartCase(name.toLowerCase())}</td> | ||
<td> | ||
<div style={{ float: 'right' }}> | ||
{formatValue(name, value, '')} | ||
</div> | ||
</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
</Table> | ||
); | ||
} else { | ||
output = ( | ||
<div style={{ float: 'right' }}> | ||
{formatValue(type, JSON.stringify(data), units[type])} | ||
</div> | ||
); | ||
} | ||
return output; | ||
} | ||
|
||
let info = <> </>; | ||
|
||
if (isOnline(props)) { | ||
const { data, batteryVoltage } = props; | ||
info = ( | ||
<> | ||
<Table hover> | ||
<tbody> | ||
{/* Battery Voltage */} | ||
<tr> | ||
<td> | ||
<strong>Battery Voltage</strong> | ||
</td> | ||
<td>{batteryVoltage ? batteryVoltage.toFixed(2) : '-'} V</td> | ||
</tr> | ||
|
||
{/* Sensors List of Names */} | ||
<tr> | ||
<td> | ||
<strong>Sensors</strong> | ||
</td> | ||
<td> | ||
{data | ||
.map(({ type }) => camelCaseToStartCase(type.toLowerCase())) | ||
.join(', ')} | ||
</td> | ||
</tr> | ||
</tbody> | ||
</Table> | ||
|
||
{/* Sensor Data Toggle Section */} | ||
<Accordion className="mt-2"> | ||
<Card> | ||
<Accordion.Toggle | ||
as={Button} | ||
variant="outline-success" | ||
eventKey="0" | ||
> | ||
Sensor Data | ||
</Accordion.Toggle> | ||
<Accordion.Collapse eventKey="0"> | ||
<Card.Body> | ||
<Table bordered hover> | ||
<tbody> | ||
{data.map(({ type, value }) => ( | ||
<tr key={`${moduleName} ${type}`}> | ||
<td> | ||
<strong> | ||
{camelCaseToStartCase(type.toLowerCase())} | ||
</strong> | ||
</td> | ||
<td>{extractData(type, value)}</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
</Table> | ||
</Card.Body> | ||
</Accordion.Collapse> | ||
</Card> | ||
</Accordion> | ||
</> | ||
); | ||
} | ||
|
||
return ( | ||
<Col md xl="12" className="my-2"> | ||
{statusPill} | ||
|
||
{/* Only show more information if the camera is online */} | ||
{info} | ||
</Col> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from 'react'; | ||
import { Card, Row } from 'react-bootstrap'; | ||
|
||
import AnemometerStatus from 'components/v3/status/AnemometerStatus'; | ||
import { useModuleStatus } from 'api/common/data'; | ||
|
||
/** | ||
* Container for Wireless Module Statuses | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to update the function documentation |
||
* | ||
* @returns Component | ||
*/ | ||
export default function AnemometerStatusContainer() { | ||
const front = useModuleStatus(1, 'Wind Speed'); | ||
const back = useModuleStatus(3, 'Wind Direction'); | ||
|
||
return ( | ||
<Card> | ||
<Card.Body> | ||
<Card.Title>Anemometer</Card.Title> | ||
<Row> | ||
{/* Front WM Status */} | ||
<AnemometerStatus {...front} /> | ||
|
||
{/* Back WM Status */} | ||
<AnemometerStatus {...back} /> | ||
</Row> | ||
</Card.Body> | ||
</Card> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -37,6 +37,14 @@ export const GyroscopeRT = Record({ | |||||
z: Number, | ||||||
}); | ||||||
|
||||||
export const AnemometerRT = Record({ | ||||||
/** Wind Speed value */ | ||||||
windSpeed: Number, | ||||||
|
||||||
/** Wind Direction value */ | ||||||
windDirection: Number, | ||||||
}); | ||||||
|
||||||
/** Value runtype of reedVelocity sensor data */ | ||||||
export const ReedVelocityRT = Number; | ||||||
|
||||||
|
@@ -92,6 +100,7 @@ export const SensorsRT = Union( | |||||
PowerRT, | ||||||
CadenceRT, | ||||||
HeartRateRT, | ||||||
AnemometerRT, | ||||||
); | ||||||
|
||||||
/** Sensor data as incoming from MQTT */ | ||||||
|
@@ -117,6 +126,9 @@ export type CO2T = Static<typeof CO2RT>; | |||||
/** Value type of accelerometer sensor data */ | ||||||
export type AccelerometerT = Static<typeof AccelerometerRT>; | ||||||
|
||||||
/** Value type of aneomometer sensor data */ | ||||||
export type AnemometerRT = Static<typeof AnemometerRT>; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
we already define a variable called In short, some places in our code accept a variable that represents our data, so we use |
||||||
|
||||||
/** Value type of gyroscope sensor data */ | ||||||
export type GyroscopeT = Static<typeof GyroscopeRT>; | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this file? We could use WMStatus.tsx to achieve the same objective...