OK it works 🎉
parent
0f57b278c7
commit
d9c44e367b
|
@ -1,7 +1,6 @@
|
|||
import { Everything } from "../../interfaces";
|
||||
|
||||
export let bot: Everything["bot"] = {
|
||||
"connectedToMQTT": true,
|
||||
"stepSize": 100,
|
||||
"controlPanelState": {
|
||||
"homing_and_calibration": false,
|
||||
|
|
|
@ -11,7 +11,10 @@ export interface EdgeStatus {
|
|||
|
||||
/** Name of a connection between two points. "." can be read as "to".
|
||||
* Example: "user.mqtt" => "User to MQTT". */
|
||||
export type Edge = "user.mqtt" | "user.api";
|
||||
export type Edge =
|
||||
| "bot.mqtt"
|
||||
| "user.mqtt"
|
||||
| "user.api";
|
||||
|
||||
/** Mapping of known connection status.
|
||||
* An `undefined` value means we don't know. */
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Actions } from "../constants";
|
|||
import { ConnectionState, EdgeStatus } from "./interfaces";
|
||||
|
||||
export const DEFAULT_STATE: ConnectionState = {
|
||||
"bot.mqtt": undefined,
|
||||
"user.mqtt": undefined,
|
||||
"user.api": undefined,
|
||||
};
|
||||
|
|
|
@ -388,7 +388,6 @@ export enum Actions {
|
|||
|
||||
// Devices
|
||||
TOGGLE_CONTROL_PANEL_OPTION = "TOGGLE_CONTROL_PANEL_OPTION",
|
||||
SET_MQTT_STATUS = "TOGGLE_MQTT",
|
||||
CHANGE_STEP_SIZE = "CHANGE_STEP_SIZE",
|
||||
SETTING_UPDATE_START = "SETTING_UPDATE_START",
|
||||
SETTING_UPDATE_END = "SETTING_UPDATE_END",
|
||||
|
|
|
@ -2,7 +2,6 @@ import { versionOK, botReducer, initialState } from "../reducer";
|
|||
import { Actions } from "../../constants";
|
||||
import { ControlPanelState } from "../interfaces";
|
||||
import { SyncStatus } from "farmbot/dist";
|
||||
import { setMqttStatus } from "../actions";
|
||||
|
||||
describe("safeStringFetch", () => {
|
||||
it("Checks the correct version on update", () => {
|
||||
|
@ -103,11 +102,4 @@ describe("botRedcuer", () => {
|
|||
.toBe(!initialState.encoder_visibility.scaled_encoders);
|
||||
|
||||
});
|
||||
|
||||
it("toggles MQTT status", () => {
|
||||
let state = botReducer(initialState, setMqttStatus(false));
|
||||
expect(state.connectedToMQTT).toBe(false);
|
||||
state = botReducer(initialState, setMqttStatus(true));
|
||||
expect(state.connectedToMQTT).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ import { versionOK } from "./reducer";
|
|||
import { oneOf, HttpData } from "../util";
|
||||
import { Actions, Content } from "../constants";
|
||||
import { mcuParamValidator } from "./update_interceptor";
|
||||
import { dispatchNetworkUp, dispatchNetworkDown } from "../connectivity/index";
|
||||
|
||||
const ON = 1, OFF = 0;
|
||||
export type ConfigKey = keyof McuParams;
|
||||
|
@ -255,6 +256,11 @@ function readStatus() {
|
|||
}
|
||||
|
||||
let NEED_VERSION_CHECK = true;
|
||||
const bothUp = () => {
|
||||
console.log("NO!");
|
||||
dispatchNetworkUp("user.mqtt");
|
||||
dispatchNetworkUp("bot.mqtt");
|
||||
};
|
||||
// Already filtering messages in FarmBot OS and the API- this is just for
|
||||
// an additional layer of safety. If sensitive data ever hits a client, it will
|
||||
// be reported to ROllbar for investigation.
|
||||
|
@ -264,9 +270,9 @@ export function connectDevice(token: string): ConnectDeviceReturn {
|
|||
return (dispatch: Function, getState: GetState) => {
|
||||
const secure = location.protocol === "https:";
|
||||
const bot = new Farmbot({ token, secure });
|
||||
bot.on("online", () => dispatch(setMqttStatus(true)));
|
||||
bot.on("online", () => dispatchNetworkUp("user.mqtt"));
|
||||
bot.on("offline", () => {
|
||||
dispatch(setMqttStatus(false));
|
||||
dispatchNetworkDown("user.mqtt");
|
||||
error(t(Content.MQTT_DISCONNECTED));
|
||||
});
|
||||
return bot
|
||||
|
@ -281,7 +287,7 @@ export function connectDevice(token: string): ConnectDeviceReturn {
|
|||
))
|
||||
.catch(() => { });
|
||||
bot.on("logs", function (msg: Log) {
|
||||
dispatch(setMqttStatus(true));
|
||||
bothUp();
|
||||
if (isLog(msg) && !oneOf(BAD_WORDS, msg.message.toUpperCase())) {
|
||||
maybeShowLog(msg);
|
||||
dispatch(init({
|
||||
|
@ -290,12 +296,22 @@ export function connectDevice(token: string): ConnectDeviceReturn {
|
|||
uuid: "MUST_CHANGE",
|
||||
body: msg
|
||||
}));
|
||||
// CORRECT SOLUTION: Give each device its own topic for publishing
|
||||
// MQTT last will message.
|
||||
// FAST SOLUTION: We would need to re-publish FBJS and FBOS to
|
||||
// change topic structure. Instead, we will use
|
||||
// inband signalling (for now).
|
||||
// TODO: Make a `bot/device_123/offline` channel.
|
||||
const died =
|
||||
msg.message.includes("is offline") && msg.meta.type === "error";
|
||||
console.log(msg.message);
|
||||
died && dispatchNetworkDown("bot.mqtt");
|
||||
} else {
|
||||
throw new Error("Refusing to display log: " + JSON.stringify(msg));
|
||||
}
|
||||
});
|
||||
bot.on("status", _.throttle(function (msg: BotStateTree) {
|
||||
dispatch(setMqttStatus(true));
|
||||
bothUp();
|
||||
dispatch(incomingStatus(msg));
|
||||
if (NEED_VERSION_CHECK) {
|
||||
const IS_OK = versionOK(getState()
|
||||
|
@ -311,7 +327,7 @@ export function connectDevice(token: string): ConnectDeviceReturn {
|
|||
|
||||
let alreadyToldYou = false;
|
||||
bot.on("malformed", function () {
|
||||
dispatch(setMqttStatus(true));
|
||||
bothUp();
|
||||
if (!alreadyToldYou) {
|
||||
warning(t(Content.MALFORMED_MESSAGE_REC_UPGRADE));
|
||||
alreadyToldYou = true;
|
||||
|
@ -414,7 +430,3 @@ export function setSyncStatus(payload: SyncStatus) {
|
|||
function badVersion() {
|
||||
info(t("You are running an old version of FarmBot OS."), t("Please Update"), "red");
|
||||
}
|
||||
|
||||
export let setMqttStatus = (payload: boolean) => ({
|
||||
type: Actions.SET_MQTT_STATUS, payload
|
||||
});
|
||||
|
|
|
@ -2,6 +2,8 @@ import {
|
|||
browserToMQTT, botToMQTT, botToAPI, botToFirmware, browserToAPI
|
||||
} from "../status_checks";
|
||||
import * as moment from "moment";
|
||||
import { ConnectionStatus } from "../../../connectivity/interfaces";
|
||||
import { betterMerge } from "../../../util";
|
||||
|
||||
describe("botToAPI()", () => {
|
||||
it("handles connectivity", () => {
|
||||
|
@ -24,8 +26,16 @@ describe("botToAPI()", () => {
|
|||
});
|
||||
|
||||
describe("botToMQTT()", () => {
|
||||
function stat(input: Partial<ConnectionStatus> = {}): ConnectionStatus {
|
||||
return betterMerge({
|
||||
from: "bot",
|
||||
to: "mqtt",
|
||||
at: "2017-09-27T07:52:37.003-05:00",
|
||||
stat: "up"
|
||||
}, input as ConnectionStatus);
|
||||
}
|
||||
it("handles connectivity", () => {
|
||||
const result = botToMQTT("\"2017-09-27T07:52:37.003-05:00\"");
|
||||
const result = botToMQTT(stat());
|
||||
expect(result.connectionStatus).toBeTruthy();
|
||||
expect(result.children).toContain("Connected ");
|
||||
expect(result.children).toContain(" ago");
|
||||
|
|
|
@ -27,23 +27,16 @@ export function botToAPI(lastSeen: moment.Moment | undefined,
|
|||
return status;
|
||||
}
|
||||
|
||||
export function botToMQTT(lastSeen: string | undefined,
|
||||
now = moment()): StatusRowProps {
|
||||
const output: StatusRowProps = {
|
||||
const NOT_SEEN = "We are not seeing any realtime messages from the bot right now.";
|
||||
export function botToMQTT(stat: ConnectionStatus | undefined): StatusRowProps {
|
||||
return {
|
||||
connectionName: "botMQTT",
|
||||
from: "Bot",
|
||||
to: "Message Broker",
|
||||
connectionStatus: false,
|
||||
children: "We are not seeing any realtime messages from the bot right now."
|
||||
connectionStatus: !!(stat && stat.state === "up"),
|
||||
children: stat ?
|
||||
`Last message seen ${moment(new Date(stat.at)).fromNow()}.` : NOT_SEEN
|
||||
};
|
||||
|
||||
if (lastSeen) {
|
||||
output.connectionStatus = true;
|
||||
const ago = moment(new Date(JSON.parse(lastSeen))).fromNow();
|
||||
output.children = `Connected ${ago}.`;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
export function browserToMQTT(online?: boolean): StatusRowProps {
|
||||
|
|
|
@ -20,16 +20,17 @@ export class Devices extends React.Component<Props, {}> {
|
|||
|
||||
/** A record of all the things we know about connectivity right now. */
|
||||
get flags(): Record<DiagnosisName, StatusRowProps> {
|
||||
const mqttConnected = this.props.bot.connectedToMQTT;
|
||||
const lastSeen = this.props.deviceAccount.body.last_seen;
|
||||
const timestamp = this.props.bot.hardware.user_env["LAST_CLIENT_CONNECTED"];
|
||||
const mqttConnected =
|
||||
this.props.userToMqtt && this.props.userToMqtt.state === "up";
|
||||
const botApiTimestamp = this.props.deviceAccount.body.last_seen;
|
||||
const fwVersion = this.props.bot.hardware
|
||||
.informational_settings.firmware_version;
|
||||
|
||||
return {
|
||||
userMQTT: browserToMQTT(mqttConnected),
|
||||
userAPI: browserToAPI(this.props.connectivity),
|
||||
botMQTT: botToMQTT(timestamp),
|
||||
botAPI: botToAPI(lastSeen ? moment(lastSeen) : undefined, moment()),
|
||||
userAPI: browserToAPI(this.props.userToApi),
|
||||
botMQTT: botToMQTT(this.props.botToMqtt),
|
||||
botAPI: botToAPI(botApiTimestamp ? moment(botApiTimestamp) : undefined, moment()),
|
||||
botFirmware: botToFirmware(fwVersion),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ import { EncoderDisplay } from "../controls/interfaces";
|
|||
import { ConnectionStatus } from "../connectivity/interfaces";
|
||||
|
||||
export interface Props {
|
||||
connectivity: ConnectionStatus | undefined;
|
||||
userToApi: ConnectionStatus | undefined;
|
||||
userToMqtt: ConnectionStatus | undefined;
|
||||
botToMqtt: ConnectionStatus | undefined;
|
||||
auth: AuthState | undefined;
|
||||
bot: BotState;
|
||||
deviceAccount: TaggedDevice;
|
||||
|
@ -39,7 +41,6 @@ export interface DeviceAccountSettings {
|
|||
}
|
||||
|
||||
export interface BotState {
|
||||
connectedToMQTT: boolean;
|
||||
/** How many steps to move when the user presses a manual movement arrow */
|
||||
stepSize: number;
|
||||
/** The current os version on the github release api */
|
||||
|
|
|
@ -26,7 +26,6 @@ export function versionOK(stringyVersion = "0.0.0",
|
|||
}
|
||||
}
|
||||
export let initialState: BotState = {
|
||||
connectedToMQTT: false,
|
||||
stepSize: 100,
|
||||
controlPanelState: {
|
||||
homing_and_calibration: false,
|
||||
|
@ -136,8 +135,4 @@ export let botReducer = generateReducer<BotState>(initialState)
|
|||
.add<EncoderDisplay>(Actions.DISPLAY_ENCODER_DATA, (s, { payload }) => {
|
||||
s.encoder_visibility[payload] = !s.encoder_visibility[payload];
|
||||
return s;
|
||||
})
|
||||
.add<boolean>(Actions.SET_MQTT_STATUS, (s, a) => {
|
||||
s.connectedToMQTT = a.payload;
|
||||
return s;
|
||||
});
|
||||
|
|
|
@ -7,7 +7,9 @@ import {
|
|||
|
||||
export function mapStateToProps(props: Everything): Props {
|
||||
return {
|
||||
connectivity: props.connectivity["user.api"],
|
||||
userToApi: props.connectivity["user.api"],
|
||||
userToMqtt: props.connectivity["user.mqtt"],
|
||||
botToMqtt: props.connectivity["bot.mqtt"],
|
||||
deviceAccount: getDeviceAccountSettings(props.resources.index),
|
||||
auth: props.auth,
|
||||
bot: props.bot,
|
||||
|
|
Loading…
Reference in New Issue