firmware hardware status indicator

pull/1144/head
gabrielburnworth 2019-04-09 19:09:57 -07:00
parent 40defc57b8
commit 224e21ebe9
7 changed files with 161 additions and 21 deletions

View File

@ -1097,3 +1097,18 @@ ul {
margin: 0.5rem !important;
}
}
.status-icon {
padding: 0.5rem;
float: right !important;
font-size: 1.75rem;
&.ok {
color: $green;
}
&.no {
color: $red;
}
&.unknown {
color: $orange;
}
}

View File

@ -1,14 +1,6 @@
import * as React from "react";
import { FarmbotOsProps, FarmbotOsState } from "../interfaces";
import {
Widget,
WidgetHeader,
WidgetBody,
Row,
Col,
SaveBtn
} from "../../ui/index";
import { Widget, WidgetHeader, WidgetBody, Row, Col, SaveBtn } from "../../ui";
import { save, edit, refresh } from "../../api/crud";
import { MustBeOnline, isBotOnline } from "../must_be_online";
import { ToolTips, Content } from "../../constants";
@ -23,7 +15,6 @@ import { AutoSyncRow } from "./fbos_settings/auto_sync_row";
import { isUndefined } from "lodash";
import { PowerAndReset } from "./fbos_settings/power_and_reset";
import { SendDiagnosticReport } from "./send_diagnostic_report";
import axios from "axios";
import { t } from "../../i18next_wrapper";
@ -97,6 +88,7 @@ export class FarmbotOsSettings
const { bot, account, sourceFbosConfig, botToMqttStatus } = this.props;
const { firmware_version, sync_status } = bot.hardware.informational_settings;
const botOnline = isBotOnline(sync_status, botToMqttStatus);
const { firmware_hardware } = bot.hardware.configuration;
return <Widget className="device-widget">
<form onSubmit={(e) => e.preventDefault()}>
<WidgetHeader title="Device" helpText={ToolTips.OS_SETTINGS}>
@ -163,6 +155,7 @@ export class FarmbotOsSettings
shouldDisplay={this.props.shouldDisplay}
dispatch={this.props.dispatch} />
<BoardType
firmwareHardware={firmware_hardware}
firmwareVersion={firmware_version}
dispatch={this.props.dispatch}
shouldDisplay={this.props.shouldDisplay}

View File

@ -24,6 +24,7 @@ describe("<BoardType/>", () => {
dispatch: jest.fn(x => x(jest.fn(), () => state)),
sourceFbosConfig: () => ({ value: true, consistent: true }),
shouldDisplay: () => false,
firmwareHardware: undefined,
});
it("Farmduino", () => {

View File

@ -0,0 +1,65 @@
import * as React from "react";
import { mount } from "enzyme";
import {
FirmwareHardwareStatusDetailsProps, FirmwareHardwareStatusDetails,
FirmwareHardwareStatusIconProps, FirmwareHardwareStatusIcon
} from "../firmware_hardware_status";
describe("<FirmwareHardwareStatusDetails />", () => {
const fakeProps = (): FirmwareHardwareStatusDetailsProps => ({
status: false,
apiFirmwareValue: undefined,
botFirmwareValue: undefined,
mcuFirmwareVersion: undefined,
mcuFirmwareValue: undefined,
});
it("renders details: inconsistent", () => {
const wrapper = mount(<FirmwareHardwareStatusDetails {...fakeProps()} />);
expect(wrapper.text()).toContain("inconsistent");
});
it("renders details: consistent", () => {
const p = fakeProps();
p.status = true;
p.apiFirmwareValue = "arduino";
p.botFirmwareValue = "arduino";
p.mcuFirmwareValue = "arduino";
const wrapper = mount(<FirmwareHardwareStatusDetails {...p} />);
expect(wrapper.text()).toContain("consistent");
expect(wrapper.text()).toContain("RAMPS");
});
});
describe("<FirmwareHardwareStatusIcon />", () => {
const fakeProps = (): FirmwareHardwareStatusIconProps => ({
firmwareHardware: undefined,
ok: false,
});
it("renders details: ok", () => {
const p = fakeProps();
p.firmwareHardware = "arduino";
p.ok = true;
const wrapper = mount(<FirmwareHardwareStatusIcon {...p} />);
expect(wrapper.find("i").hasClass("ok")).toEqual(true);
expect(wrapper.find("i").hasClass("fa-check-circle")).toEqual(true);
});
it("renders details: inconsistent", () => {
const p = fakeProps();
p.firmwareHardware = "arduino";
p.ok = false;
const wrapper = mount(<FirmwareHardwareStatusIcon {...p} />);
expect(wrapper.find("i").hasClass("no")).toEqual(true);
expect(wrapper.find("i").hasClass("fa-times-circle")).toEqual(true);
});
it("renders details: unknown", () => {
const p = fakeProps();
p.firmwareHardware = undefined;
const wrapper = mount(<FirmwareHardwareStatusIcon {...p} />);
expect(wrapper.find("i").hasClass("unknown")).toEqual(true);
expect(wrapper.find("i").hasClass("fa-question-circle")).toEqual(true);
});
});

View File

@ -1,6 +1,5 @@
import * as React from "react";
import { Row, Col, DropDownItem, FBSelect } from "../../../ui/index";
import { Row, Col, DropDownItem, FBSelect } from "../../../ui";
import { info } from "farmbot-toastr";
import { FirmwareHardware } from "farmbot";
import { ColWidth } from "../farmbot_os_settings";
@ -8,6 +7,7 @@ import { updateConfig } from "../../actions";
import { BoardTypeProps } from "./interfaces";
import { Feature } from "../../interfaces";
import { t } from "../../../i18next_wrapper";
import { FirmwareHardwareStatus } from "./firmware_hardware_status";
const ARDUINO = { label: "Arduino/RAMPS (Genesis v1.2)", value: "arduino" };
const FARMDUINO = { label: "Farmduino (Genesis v1.3)", value: "farmduino" };
@ -15,7 +15,7 @@ const FARMDUINO_K14 = {
label: "Farmduino (Genesis v1.4)", value: "farmduino_k14"
};
const FIRMWARE_CHOICES_DDI = {
export const FIRMWARE_CHOICES_DDI = {
[ARDUINO.value]: ARDUINO,
[FARMDUINO.value]: FARMDUINO,
[FARMDUINO_K14.value]: FARMDUINO_K14
@ -40,7 +40,8 @@ export class BoardType extends React.Component<BoardTypeProps, BoardTypeState> {
}
get apiValue() {
return this.props.sourceFbosConfig("firmware_hardware").value;
const { value } = this.props.sourceFbosConfig("firmware_hardware");
return typeof value === "string" ? value : undefined;
}
get firmwareChoices() {
@ -55,11 +56,11 @@ export class BoardType extends React.Component<BoardTypeProps, BoardTypeState> {
const boardIdentifier = this.props.firmwareVersion.slice(-1);
switch (boardIdentifier) {
case "R":
return "Arduino/RAMPS";
return "arduino";
case "F":
return "Farmduino";
return "farmduino";
case "G":
return "Farmduino k1.4";
return "farmduino_k14";
default:
return "unknown";
}
@ -70,15 +71,15 @@ export class BoardType extends React.Component<BoardTypeProps, BoardTypeState> {
get selectedBoard(): DropDownItem | undefined {
switch (this.state.boardType) {
case "Arduino/RAMPS":
case "arduino":
return FIRMWARE_CHOICES_DDI["arduino"];
case "Farmduino":
case "farmduino":
return FIRMWARE_CHOICES_DDI["farmduino"];
case "Farmduino k1.4":
case "farmduino_k14":
return FIRMWARE_CHOICES_DDI["farmduino_k14"];
case "unknown":
// If unknown/disconnected, display API FirmwareHardware value if valid
return (this.sending && typeof this.apiValue === "string")
return (this.sending && this.apiValue)
? FIRMWARE_CHOICES_DDI[this.apiValue]
: undefined;
default:
@ -119,6 +120,13 @@ export class BoardType extends React.Component<BoardTypeProps, BoardTypeState> {
onChange={this.sendOffConfig} />
</div>
</Col>
<Col xs={ColWidth.button}>
<FirmwareHardwareStatus
apiFirmwareValue={this.apiValue}
botFirmwareValue={this.props.firmwareHardware}
mcuFirmwareVersion={this.props.firmwareVersion}
mcuFirmwareValue={this.boardType} />
</Col>
</Row>;
}
}

View File

@ -0,0 +1,57 @@
import * as React from "react";
import { Popover, Position } from "@blueprintjs/core";
import { FIRMWARE_CHOICES_DDI } from "./board_type";
export interface FirmwareHardwareStatusIconProps {
firmwareHardware: string | undefined;
ok: boolean;
}
export const FirmwareHardwareStatusIcon =
(props: FirmwareHardwareStatusIconProps) => {
const okNoStatus = props.ok ? "ok" : "no";
const status = props.firmwareHardware ? okNoStatus : "unknown";
const okNoIcon = props.ok ? "fa-check-circle" : "fa-times-circle";
const icon = props.firmwareHardware ? okNoIcon : "fa-question-circle";
return <i className={`fa ${icon} status-icon ${status}`} title={status} />;
};
const lookup = (value: string | undefined) =>
value && Object.keys(FIRMWARE_CHOICES_DDI).includes(value)
? FIRMWARE_CHOICES_DDI[value].label : undefined;
export interface FirmwareHardwareStatusDetailsProps
extends FirmwareHardwareStatusProps {
status: boolean;
}
export const FirmwareHardwareStatusDetails =
(props: FirmwareHardwareStatusDetailsProps) =>
<div>
<label>{"API"}</label>
<p>{`${props.apiFirmwareValue}: ${lookup(props.apiFirmwareValue)}`}</p>
<label>{"FBOS"}</label>
<p>{`${props.botFirmwareValue}: ${lookup(props.botFirmwareValue)}`}</p>
<label>{"MCU"}</label>
<p>{`${props.mcuFirmwareVersion}: ${lookup(props.mcuFirmwareValue)}`}</p>
<label>{"STATUS"}</label>
<p>{props.status ? "consistent" : "inconsistent"}</p>
</div>;
interface FirmwareHardwareStatusProps {
apiFirmwareValue: string | undefined;
botFirmwareValue: string | undefined;
mcuFirmwareVersion: string | undefined;
mcuFirmwareValue: string | undefined;
}
export const FirmwareHardwareStatus = (props: FirmwareHardwareStatusProps) => {
const status = props.apiFirmwareValue == props.botFirmwareValue &&
props.apiFirmwareValue == props.mcuFirmwareValue;
return <Popover position={Position.BOTTOM}>
<FirmwareHardwareStatusIcon
firmwareHardware={props.botFirmwareValue}
ok={status} />
<FirmwareHardwareStatusDetails status={status} {...props} />
</Popover>;
};

View File

@ -28,6 +28,7 @@ export interface CameraSelectionState {
export interface BoardTypeProps {
firmwareVersion: string | undefined;
firmwareHardware: string | undefined;
dispatch: Function;
shouldDisplay: ShouldDisplay;
sourceFbosConfig: SourceFbosConfig;