<commit_before>import { Farmbot } from "farmbot";
import { t } from "i18next";
import axios from "axios";
import * as _ from "lodash";
import { success, warning, info, error } from "farmbot-toastr";
import { devices } from "../device";
import { Log } from "../interfaces";
import { GithubRelease, MoveRelProps } from "./interfaces";
import { Thunk, GetState } from "../redux/interfaces";
import { DeviceAccountSettings, BotState } from "../devices/interfaces";
import {
  McuParams,
  Configuration,
  BotStateTree,
  ALLOWED_CHANNEL_NAMES,
  ALLOWED_MESSAGE_TYPES,
  SyncStatus
} from "farmbot";
import { Sequence } from "../sequences/interfaces";
import { HardwareState, ControlPanelState } from "../devices/interfaces";
import { API } from "../api/index";
import { User } from "../auth/interfaces";
import { init, edit } from "../api/crud";
import { getDeviceAccountSettings } from "../resources/selectors";
import { TaggedDevice } from "../resources/tagged_resources";
import { versionOK } from "./reducer";
import { oneOf, HttpData } from "../util";
import { Actions } from "../constants";

const ON = 1, OFF = 0;
type configKey = keyof McuParams;
export const EXPECTED_MAJOR = 5;
export const EXPECTED_MINOR = 0;

function incomingStatus(statusMessage: HardwareState) {
  return { type: "BOT_CHANGE", payload: statusMessage };
}

export function isLog(x: object): x is Log {
  return _.isObject(x) && _.isString(_.get(x, "message" as keyof Log));
}
let commandErr = (noun = "Command") => (x: any) => {
  console.dir(x);
  console.info("Took longer than 6 seconds: " + noun);
};

let commandOK = (noun = "Command") => () => {
  let msg = noun + " request sent to device.";
  success(msg, t("Request sent"));
};

export function checkControllerUpdates() {
  let noun = "Check for Updates";
  devices
    .current
    .checkUpdates()
    .then(commandOK(noun), commandErr(noun));
}

export function powerOff() {
  let noun = "Power Off Bot";
  devices
    .current
    .powerOff()
    .then(commandOK(noun), commandErr(noun));
}

export function factoryReset() {
  if (!confirm(`WAIT! This will erase EVERYTHING stored on your device SD card.
  Are you sure?`)) {
    return;
  }
  devices
    .current
    .resetOS();
}

export function reboot() {
  let noun = "Reboot Bot";
  devices
    .current
    .reboot()
    .then(commandOK(noun), commandErr(noun));
}

export function emergencyLock() {
  let noun = "Emergency stop";
  devices
    .current
    .emergencyLock()
    .then(commandOK(noun), commandErr(noun));
}

export function emergencyUnlock() {
  let noun = "Emergency unlock";
  if (confirm(`Are you sure you want to unlock the device?`)) {
    devices
      .current
      .emergencyUnlock()
      .then(commandOK(noun), commandErr(noun));
  }
}

export function sync(): Thunk {
  let noun = "Sync";
  return function (dispatch, getState) {
    let IS_OK = versionOK(getState()
      .bot
      .hardware
      .informational_settings
      .controller_version, EXPECTED_MAJOR, EXPECTED_MINOR);
    if (IS_OK) {
      dispatch(setSyncStatus("syncing"));
      devices
        .current
        .sync()
        .then(() => {
          commandOK(noun);
          dispatch(setSyncStatus("synced"));
        }).catch(() => {
          commandErr(noun);
          dispatch(setSyncStatus("sync_error"));
        });
    } else {
      badVersion();
    }
  };
}

export function execSequence(sequence: Sequence) {
  const noun = "Sequence execution";
  if (sequence.id) {
    return devices
      .current
      .execSequence(sequence.id)
      .then(commandOK(noun), commandErr(noun));
  } else {
    throw new Error("Can't execute unsaved sequences");
  }
}

export let saveAccountChanges: Thunk = function (dispatch, getState) {
  return save(getDeviceAccountSettings(getState().resources.index));
};

export let fetchReleases =
  (url: string) => (dispatch: Function, getState: Function) => {
    axios
      .get(url)
      .then((resp: HttpData<GithubRelease>) => {
        let version = resp.data.tag_name;
        let versionWithoutV = version.slice(1, version.length);
        dispatch({
          type: "FETCH_OS_UPDATE_INFO_OK",
          payload: versionWithoutV
        });
      })
      .catch((ferror) => {
        error(t("Could not download firmware update information."));
        dispatch({
          type: "FETCH_OS_UPDATE_INFO_ERROR",
          payload: ferror
        });
      });
  };

export function save(input: TaggedDevice) {
  return function (dispatch: Function, getState: GetState) {
    return axios
      .put(API.current.devicePath, input.body)
      .then((resp: HttpData<User>) => dispatch({ type: "SAVE_DEVICE_OK", payload: resp.data }))
      .catch(resp => error("Error saving device settings."));
  };
}

/**
 * Toggles visibility of individual sections in the giant controls panel<commit_msg>HOTFIX I: Dont show "up to date" all the time<commit_after>import { Farmbot } from "farmbot";
import { t } from "i18next";
import axios from "axios";
import * as _ from "lodash";
import { success, warning, info, error } from "farmbot-toastr";
import { devices } from "../device";
import { Log } from "../interfaces";
import { GithubRelease, MoveRelProps } from "./interfaces";
import { Thunk, GetState } from "../redux/interfaces";
import { DeviceAccountSettings, BotState } from "../devices/interfaces";
import {
  McuParams,
  Configuration,
  BotStateTree,
  ALLOWED_CHANNEL_NAMES,
  ALLOWED_MESSAGE_TYPES,
  SyncStatus
} from "farmbot";
import { Sequence } from "../sequences/interfaces";
import { HardwareState, ControlPanelState } from "../devices/interfaces";
import { API } from "../api/index";
import { User } from "../auth/interfaces";
import { init, edit } from "../api/crud";
import { getDeviceAccountSettings } from "../resources/selectors";
import { TaggedDevice } from "../resources/tagged_resources";
import { versionOK } from "./reducer";
import { oneOf, HttpData } from "../util";
import { Actions } from "../constants";

const ON = 1, OFF = 0;
type configKey = keyof McuParams;
export const EXPECTED_MAJOR = 5;
export const EXPECTED_MINOR = 0;

function incomingStatus(statusMessage: HardwareState) {
  return { type: "BOT_CHANGE", payload: statusMessage };
}

export function isLog(x: object): x is Log {
  return _.isObject(x) && _.isString(_.get(x, "message" as keyof Log));
}
let commandErr = (noun = "Command") => (x: any) => {
  console.dir(x);
  console.info("Took longer than 6 seconds: " + noun);
};

let commandOK = (noun = "Command") => () => {
  let msg = noun + " request sent to device.";
  success(msg, t("Request sent"));
};

export function checkControllerUpdates() {
  let noun = "Check for Updates";
  devices
    .current
    .checkUpdates()
    .then(commandOK(noun), commandErr(noun));
}

export function powerOff() {
  let noun = "Power Off Bot";
  devices
    .current
    .powerOff()
    .then(commandOK(noun), commandErr(noun));
}

export function factoryReset() {
  if (!confirm(`WAIT! This will erase EVERYTHING stored on your device SD card.
  Are you sure?`)) {
    return;
  }
  devices
    .current
    .resetOS();
}

export function reboot() {
  let noun = "Reboot Bot";
  devices
    .current
    .reboot()
    .then(commandOK(noun), commandErr(noun));
}

export function emergencyLock() {
  let noun = "Emergency stop";
  devices
    .current
    .emergencyLock()
    .then(commandOK(noun), commandErr(noun));
}

export function emergencyUnlock() {
  let noun = "Emergency unlock";
  if (confirm(`Are you sure you want to unlock the device?`)) {
    devices
      .current
      .emergencyUnlock()
      .then(commandOK(noun), commandErr(noun));
  }
}

export function sync(): Thunk {
  let noun = "Sync";
  return function (dispatch, getState) {
    let IS_OK = versionOK(getState()
      .bot
      .hardware
      .informational_settings
      .controller_version, EXPECTED_MAJOR, EXPECTED_MINOR);
    if (IS_OK) {
      dispatch(setSyncStatus("syncing"));
      devices
        .current
        .sync()
        .then(() => {
          commandOK(noun);
          dispatch(setSyncStatus("synced"));
        }).catch(() => {
          commandErr(noun);
          dispatch(setSyncStatus("sync_error"));
        });
    } else {
      badVersion();
    }
  };
}

export function execSequence(sequence: Sequence) {
  const noun = "Sequence execution";
  if (sequence.id) {
    return devices
      .current
      .execSequence(sequence.id)
      .then(commandOK(noun), commandErr(noun));
  } else {
    throw new Error("Can't execute unsaved sequences");
  }
}

export let saveAccountChanges: Thunk = function (dispatch, getState) {
  return save(getDeviceAccountSettings(getState().resources.index));
};

export let fetchReleases =
  (url: string) => (dispatch: Function, getState: Function) => {
    axios
      .get(url)
      .then((resp: HttpData<GithubRelease>) => {
        let version = resp.data.tag_name;
        let versionWithoutV = version.toLowerCase().replace("v", "");
        dispatch({
          type: "FETCH_OS_UPDATE_INFO_OK",
          payload: versionWithoutV
        });
      })
      .catch((ferror) => {
        error(t("Could not download firmware update information."));
        dispatch({
          type: "FETCH_OS_UPDATE_INFO_ERROR",
          payload: ferror
        });
      });
  };

export function save(input: TaggedDevice) {
  return function (dispatch: Function, getState: GetState) {
    return axios
      .put(API.current.devicePath, input.body)
      .then((resp: HttpData<User>) => dispatch({ type: "SAVE_DEVICE_OK", payload: resp.data }))
      .catch(resp => error("Error saving device settings."));
  };
}

/**
 * Toggles visibility of individual sections in the giant controls panel
{'fraction_non_alphanumeric': 0.1414027149321267, 'fraction_numerical': 0.0015425750719868367, 'mean_word_length': 3.2541557305336832, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2845927', 'n_tokens_mistral': 3035, 'n_tokens_neox': 2975, 'n_words': 801}