Merge pull request #1099 from FarmBot/rel-9.0.0

Release v9.0.0, Jolly Juniper
pull/1101/head v9.0.0
Rick Carlino 2019-12-30 12:58:07 -06:00 committed by GitHub
commit 398f15c452
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
161 changed files with 5169 additions and 1212 deletions

View File

@ -56,6 +56,14 @@ install_libnl: &install_libnl
apt-get update
apt-get install pkg-config libnl-genl-3-dev -y
install_mdl: &install_mdl
run:
name: Install libnl
command: |
apt-get update
apt-get install ruby -y
gem install mdl
build_firmware_steps: &build_firmware_steps
steps:
- checkout
@ -376,6 +384,7 @@ jobs:
- run: git submodule update --init --recursive
- <<: *install_elixir
- <<: *install_hex_archives
- <<: *install_mdl
- restore_cache:
keys:
- v14-fbsupport-test-dependency-cache-{{ checksum "mix.lock" }}
@ -397,6 +406,10 @@ jobs:
- restore_cache:
keys:
- v14-fbos-coverage-cache-{{ .Branch }}-{{ .Revision }}
- run:
name: Check documentation formatting
command: |
mdl docs/
- run:
name: Report Coverage
working_directory: /nerves/build/

View File

@ -1,5 +1,10 @@
# Changelog
# 9.0.0
* Run updates on Nerves systems.
* Updates to the way `set_servo_angle` is handled.
* Fixes rip0 firmware flash issues.
# 8.2.4
* Bug fixes
* fix Farmware causing sequences to exit

View File

@ -1,2 +1,4 @@
# Contributing
To get started, <a href="https://www.clahub.com/agreements/FarmBot/farmbot_os">sign the Contributor License Agreement</a>.
After that, read through the [documentation](docs/index.md)

View File

@ -10,6 +10,7 @@
"endstop_invert": "6.4.1",
"express_k10": "8.0.0",
"farmduino_k14": "6.4.4",
"farmduino_k15": "9.0.0",
"firmware_restart": "8.0.0",
"flash_firmware": "8.0.0",
"groups": "8.1.0",

View File

@ -1,4 +1,4 @@
.PHONY: all clean format
.PHONY: all clean format docs deps
.DEFAULT_GOAL: all
MIX_ENV := $(MIX_ENV)
@ -51,6 +51,12 @@ format:
deps:
@for project in $(PROJECTS) ; do \
echo Fetching deps: $$project ; \
echo Fetching deps for $$project ; \
cd $$project && mix deps.get && cd .. ; \
done
docs:
@for project in $(PROJECTS) ; do \
echo Building docs for $$project ; \
cd $$project && mix docs && cd .. ; \
done

View File

@ -12,7 +12,7 @@ Download the version of FarmBot OS that corresponds to the FarmBot kit and compu
| FarmBot Kit | Computer | Download Link |
| --- | --- | --- |
| Genesis v1.2, Genesis v1.3, Genesis v1.4, Genesis XL v1.4 | Raspberry Pi 3 | [Download FBOS](https://github.com/FarmBot/farmbot_os/releases/download/v8.2.3/farmbot-rpi3-8.2.3.img) |
| Genesis v1.2, Genesis v1.3, Genesis v1.4, Genesis XL v1.4 | Raspberry Pi 3 | [Download FBOS](https://github.com/FarmBot/farmbot_os/releases/download/v9.0.0/farmbot-rpi3-9.0.0.img) |
| Express v1.0, Express XL v1.0 | Raspberry Pi Zero W | Coming soon |
---
@ -49,8 +49,8 @@ _Refer to the [software documentation Configurator page](https://software.farm.b
## Problems?
See the [FAQ](docs/FAQ.md)
If your problem isn't solved there please file an issue on [Github](https://github.com/FarmBot-Labs/farmbot_os/issues/new)
See the [FAQ](docs/target_development/target_faq.md)
If your problem isn't solved there please file an issue on [Github](https://github.com/FarmBot/farmbot_os/issues/new)
## Security Concerns?
@ -58,5 +58,5 @@ We take security seriously and value the input of independent researchers. Pleas
## Want to Help?
[Low Hanging Fruit](https://github.com/FarmBot-Labs/farmbot_os/search?utf8=%E2%9C%93&q=TODO)
[Low Hanging Fruit](https://github.com/FarmBot/farmbot_os/search?utf8=%E2%9C%93&q=TODO)
[Development](CONTRIBUTING.md)

View File

@ -1 +1 @@
8.2.4
9.0.0

View File

@ -1,29 +0,0 @@
# Starting FarmbotOS in `host` env.
Certain behaviour is slightly different when developing on `host` compared to
deploying on target environments such as `rpi` or `rpi3`.
## Firmware
By default, an Arduino does _not_ need to be connected to your `host` pc when
doing development. See the `FarmbotFirmware.Transport` module for more info
on this topic. If you want to use a real Arduino in `host` mode, you can
export a `FARMBOT_TTY` environment variable in your `host` environment.
```bash
$ cd farmbot_os
$ export FARMBOT_TTY=/dev/ttySomeDeviceFile
$ mix compile --force
```
If you're device moves ttys, you will have to redo this step.
## Configurator
Currently configurator does not run on the `host` enviornment. To connect to
your FarmBot account, export the following variables:
```bash
$ cd farmbot_os
$ export FARMBOT_EMAIL=test@test.com
$ export FARMBOT_PASSWORD=password123
$ export FARMBOT_SERVER=http://localhost:3000
```

View File

@ -1,43 +0,0 @@
# SSH
## Setup
FarmBot can be configured to start an SSH server to aid in debugging and development.
During configuration of Network, select `Advanced Settings` and paste your [ssh
public key](https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key) into the
optional input section labeled: `id_rsa.pub`. FarmBot requires a public key and
will not allow a username + password combination. FarmBot also only allows one
key to be configured for security reasons.
## Connecting
From the same machine that owns the `id_rsa.pub` key and assosiated private key
you can simply `ssh <ip address>`. If your machine supports `mdns`, you can also
do `ssh farmbot-<node_name>` where `node_name` can be found in the `Device` panel
on the FarmBot web app.
## Usage
The console a user will be presented with is _not_ a Linux console. There are
pretty much no Linux Utilities built-in. This includes but is not limited to:
* `bash`
* `apt-get`
* `make`
* `screen`
* `vi`
* `cp`
* `mkdir`
* `ln`
* `echo`
* etc
What is available is a console to the FarmBot OS runtime. You will need to be
familiar with the FarmBotOS Source code for this to be helpful.
If all you are looking for is Logs, you will probably want to do:
```elixir
RingLogger.attach()
```
After that command you will see logs come across the screen in real time.
To exit the SSH session, type `~.`.
This is an ssh escape sequence (See the ssh man page for other escape sequences).
Typing Ctrl+D or logoff at the IEx prompt to exit the session aren't implemented.

View File

@ -1,73 +1,88 @@
# All CeleryScript Nodes
This list is split into three categories.
* RPC Nodes - Nodes that control Farmbot's state, but don't don't command
a real world side effect. This includes:
* updating configuration data.
* syncing.
* starting/stopping a process of some sort.
* rebooting
* Command Nodes - Nodes that physically do something. This includes:
* moving the gantry.
* writing or reading a GPIO.
* Data Nodes - Nodes that simply contain data. They are not to be executed.
This includes:
* explanation
* location data
## RPC Nodes
| Name | Args | Body |
|:-------------------------------|:-------------------------------------:|:-------------------------:|
| `check_updates` | `package` | --- |
| `config_update` | `package` | `pair` |
| `uninstall_farmware` | `package` | --- |
| `update_farmware` | `package` | --- |
| `rpc_request` | `label` | more command or rpc nodes |
| `rpc_ok` | `label` | --- |
| `rpc_error` | `label` | `explanation` |
| `install farmware` | `url` | --- |
| `read_status` | --- | --- |
| `sync` | --- | --- |
| `power_off` | --- | --- |
| `reboot` | --- | --- |
| `factory_reset` | --- | --- |
| `set_usr_env` | --- | `pair` |
| `install_first_party_farmware` | --- | --- |
| `change_ownership` | --- | `pair` |
| `dump_info` | --- | --- |
Nodes that control Farmbot's state, but don't don't command
a real world side effect. This includes:
* updating configuration data.
* syncing.
* starting/stopping a process of some sort.
* rebooting
### RPC Node Table
| Name | Args | Body |
|:-: | :--:|:--:|
| `check_updates`| `package`| ---|
| `config_update`| `package`| `pair`|
| `uninstall_farmware`| `package`| ---|
| `update_farmware`| `package`| ---|
| `rpc_request`| `label`| `command` or `rpc` nodes|
| `rpc_ok`| `label`| ---|
| `rpc_error`| `label`| `explanation`|
| `install farmware`| `url`| ---|
| `read_status`| --- | ---|
| `sync`| --- | ---|
| `power_off`| --- | ---|
| `reboot`| --- | ---|
| `factory_reset`| --- | ---|
| `set_usr_env`| --- | `pair`|
| `install_first_party_farmware`|---|---|
| `change_ownership`| --- | `pair`|
| `dump_info`| --- | ---|
## Command Nodes
| Name | Args | Body |
|:-------------------------------|:-------------------------------------:|:-------------------------:|
| `_if` | `lhs`, `op`, `rhs`, `_then`, `_else` | `pair` |
| `write_pin` | `pin_number`, `pin_value`, `pin_mode` | --- |
| `read_pin` | `pin_number`, `pin_value`, `pin_mode` | --- |
| `move_absolute` | `location`, `speed`, `offset` | --- |
| `set_servo_angle` | `pin_number`, `pin_value` | --- |
| `send_message` | `message`, `message_type` | `channel` |
| `move_relative` | `speed`, `x`, `y`, `z` | --- |
| `sequence` | `version`, `locals` | more command nodes |
| `home` | `speed`, `axis` | --- |
| `find_home` | `speed`, `axis` | --- |
| `wait` | `milliseconds` | --- |
| `execute` | `sequence_id` | --- |
| `toggle_pin` | `pin_number` | --- |
| `execute_script` | `package` | `pair` |
| `zero` | `axis` | --- |
| `calibrate` | `axis` | --- |
| `emergency_lock` | --- | --- |
| `emergency_unlock` | --- | --- |
| `take_photo` | --- | --- |
Nodes that physically do something. This includes:
* moving the gantry.
* writing or reading a GPIO.
### Command Node Table
| Name | Args | Body |
|:-: | :--:|:--:|
| `_if`| `lhs`, `op`, `rhs`, `_then`, `_else`| `pair`|
| `write_pin`| `pin_number`, `pin_value`, `pin_mode`| ---|
| `read_pin`| `pin_number`, `pin_value`, `pin_mode`| ---|
| `move_absolute`| `location`, `speed`, `offset`| ---|
| `set_servo_angle`| `pin_number`, `pin_value`| ---|
| `send_message`| `message`, `message_type`| `channel`|
| `move_relative`| `speed`, `x`, `y`, `z`| ---|
| `sequence`| `version`, `locals`| `any command node`|
| `home`| `speed`, `axis`| ---|
| `find_home`| `speed`, `axis`| ---|
| `wait`| `milliseconds`| ---|
| `execute`| `sequence_id`| ---|
| `toggle_pin`| `pin_number`| ---|
| `execute_script`| `package`| `pair`|
| `zero`| `axis`| ---|
| `calibrate`| `axis`| ---|
| `emergency_lock`| ---| ---|
| `emergency_unlock`| ---| ---|
| `take_photo`| ---| ---|
## Data Nodes
| Name | Args | Body |
|:-------------------------------|:-------------------------------------:|:-------------------------:|
| `point` | `pointer_type`, `pointer_id` | --- |
| `named_pin` | `pin_type`, `pin_id` | --- |
| `pair` | `label`, `value` | --- |
| `channel` | `channel_name` | --- |
| `coordinate` | `x`, `y`, `z` | --- |
| `tool` | `tool_id` | --- |
| `explanation` | `message` | --- |
| `identifier` | `label` | --- |
| `nothing` | --- | --- |
| `scope_declaration` | --- | `parameter_decleration`, `variable_decleration` |
Nodes that simply contain data. They are not to be executed. This includes:
* explanation
* location data
### Data Node Table
| Name | Args | Body |
|:-: | :--:|:--:|
| `point`| `pointer_type`, `pointer_id`| ---|
| `named_pin`| `pin_type`, `pin_id`| ---|
| `pair`| `label`, `value`| ---|
| `channel`| `channel_name`| ---|
| `coordinate`| `x`, `y`, `z`| ---|
| `tool`| `tool_id`| ---|
| `explanation`| `message`| ---|
| `identifier`| `label`| ---|
| `nothing`| ---| ---|
| `scope_declaration`| ---| `parameter_decleration` or `variable_decleration`|

View File

@ -1,12 +1,13 @@
# CeleryScript Assert expressions.
# CeleryScript Assert expressions
The CeleryScript `if` block takes a possible left hand side value of
`expression` which allows an arbitrary string to be evaluated. This
expression is evaluated against a lua 5.2 interpreter.
`expression` which allows an arbitrary string to be evaluated. This
expression is evaluated against a lua 5.2 interpreter.
## Lua API
The following functions are available for usage along with [Lua's
standard library](https://www.lua.org/manual/5.2/).
The following functions are available for usage along with
[Lua's standard library](https://www.lua.org/manual/5.2/).
```lua
-- Comments are ignored by the interpreter
@ -139,8 +140,10 @@ update_firmware_config({encoder_enabled_z = 1.0});
```
## Expression contract
Expressions are expected to be evaluated in a certain way. The evaluation will fail
if this contract is not met. An expression should return one of the following values:
* `true`
* `false`
* `("error", "string reason signaling an error happened")`

View File

@ -1,4 +1,5 @@
# CeleryScript
CeleryScript is an AST definition of commands, rpcs, and functions that
can all be executed by Farmbot. The basic syntax is as follows:
@ -16,7 +17,9 @@ optional, `body` should be supplied when working with any and all modules
in this project.
## kind
`kind` is the identifier for a command. Examples include:
* `move_absolute`
* `sync`
* `read_status`
@ -26,8 +29,10 @@ Each `kind` will have it's own set of rules for execution. These rules will
define what is required inside of both `args` and `body`.
## args
`args` is arguments to be passed to `kind`. Each `kind` defines it's own
set of optional and required `args`. Args can any of the following types:
* `number`
* `string` (with possible enum types)
* `boolean`
@ -35,6 +40,7 @@ set of optional and required `args`. Args can any of the following types:
in the case of another AST, that AST will likely need to be evaluated before
executing the parent AST. Examples of `args` include:
* `x`
* `y`
* `z`
@ -42,9 +48,11 @@ executing the parent AST. Examples of `args` include:
* `milliseconds`
## body
`body` is the only way a `list` or `array` type is aloud in CeleryScript.
It may only contain _more CeleryScript nodes_. This is useful for
enumeration, scripting looping etc. Here's a syntacticly correct example:
```elixir
%{
kind: :script,
@ -59,6 +67,7 @@ enumeration, scripting looping etc. Here's a syntacticly correct example:
Note there is nesting limit for CeleryScript body nodes, and nodes can
even be self referential. Example:
```elixir
%{
kind: :self_referencing_script,
@ -67,4 +76,4 @@ even be self referential. Example:
%{kind: :execute_self_referencing_script, args: %{id: 1}, body: []}
]
}
```
```

52
docs/glossary.md 100644
View File

@ -0,0 +1,52 @@
# FarmBot OS Source Glossary
This file contains a basic glossary of commonly used terms
## FarmBot Specific Terms
* Asset - REST resource stored in Farmbot's database stored on the SD card
* Arduino Firmware - The code that runs on the Arduino.
* [Source](https://github.com/farmbot/farmbot-arduino-firmware)
* CelleryScript - FarmBot OS's scripting language
* FarmbBot API/Web App - The REST server FarmBot communicates with
## General Terms
* Elixir - Programming language FarmBot is developed in
* [More info](https://elixir-lang.org/)
* [Docs](https://hexdocs.pm/elixir/Kernel.html)
* Erlang - Programming language and VM that Elixir compiles down too
* [More info](https://elixir-lang.org/)
* [Even more info](#OTP-Terms)
* [Docs](https://www.erlang.org/docs)
* UART - **U**niversal **A**synchronous **R**eceiver/**T**ransmitter.
hardware based transport mechanism
* SSH - **S**ecure **S**hell.
* MQTT/AMQP - network protocols for pub/sub data transport
* HTTP - network protocol for accessing REST resource
## Nerves Specific Terms
* Nerves - Framework that allows cross compilation of Elixir code
* [More info](https://nerves-project.org/)
* [Docs](https://hexdocs.pm/nerves/getting-started.html)
* NervesHub - Cloud based firmware management
* [More info](https://www.nerves-hub.org/)
* [Docs](https://github.com/nerves-hub/documentation)
* Firmware - Usually refers to the code that gets deployed onto the Raspberry Pi
## OTP Terms
* Beam - Virtual machine that runs compiled Erlang bytecode
* OTP - Open Telecom Platform. Erlang's runtime libraries
* [More info](https://erlang.org/doc/design_principles/des_princ.html)
* Supervisor - OTP `Process` responsible for supervising `Workers`
* Worker - OTP `Process` responsible for doing `work`. Usually `Supervised`
* Process - OTP concept responsible for sending/receiving messages.
**everything** is a process in erlang
* Application - OTP concept responsible for containing many `Supervisor`s and `Worker`s
* Distribution - OTP concept of networking multiple Beam instances together
* ETS - **E**rlang **T**erm **S**torage. OTP application for storing
data in memory
* DETS - **D**isk **E**rlang **T**erm **S**torage. OTP application for
storing data on disk

View File

@ -0,0 +1,50 @@
# Starting FarmbotOS in `host` env
Certain behaviour is slightly different when developing on `host` compared to
deploying on target environments such as `rpi` or `rpi3`.
## Firmware
By default, an Arduino does _not_ need to be connected to your `host` pc when
doing development. See the `FarmbotFirmware.Transport` module for more info
on this topic. If you want to use a real Arduino in `host` mode, you can
export a `FARMBOT_TTY` environment variable in your `host` environment.
```bash
cd farmbot_os
export FARMBOT_TTY=/dev/ttySomeDeviceFile
mix compile --force
```
If you're device moves ttys, you will have to redo this step.
Make sure the correct firmware is selected in the frontend. This
value is completely ignored when the `none` option is selected on
the Devices panel.
To check the currently running firmware handler, from a running fbos instance
for the correct `transport` and correct `device` in it's args:
```elixir
iex()> :sys.get_state(FarmbotFirmware)
%FarmbotFirmware{
#...
transport: FarmbotFirmware.UARTTransport,
transport_args: [
handle_gcode: #Function<1.52136448/1 in FarmbotFirmware.handle_call/3>,
device: "ttyUSB0"
]
#...
}
```
## Configurator
Currently configurator does not run on the `host` enviornment. To connect to
your FarmBot account, export the following variables:
```bash
cd farmbot_os
export FARMBOT_EMAIL=test@test.com
export FARMBOT_PASSWORD=password123
export FARMBOT_SERVER=http://localhost:3000
```

39
docs/index.md 100644
View File

@ -0,0 +1,39 @@
# FarmBot OS Documentation
This document will act as an index to available documentation.
## Glossary
* [FarmBot Source Code common terms](/docs/glossary.md)
## Hardware specifics
Most FarmBot development/testing is done on a standard desktop PC.
* [Developing on your local PC](/docs/host_development/host_development.md)
* [Deploying on Raspberry Pi](/docs/target_development/building_target_firmware.md)
* [Provisioning OTA system](/docs/target_development/provisioning_ota_system.md)
* [Publishing Firmware (OTAs)](/docs/target_development/releasing_target_firmware.md)
* [Why doesn't my device boot after building firmware](docs/target_development/target_faq.md)
* [Inspecting a running devicve](/docs/target_development/consoles/target_console.md)
## CeleryScript
CeleryScript is FarmBot's native scripting language. See the below
documentation for information about it as it relates to FarmBot OS.
* [CeleryScript intro](/docs/celery_script/celery_script.md)
* [A list of all supported commands](/docs/celery_script/all_nodes.md)
* [Lua (embedded scripting inside CeleryScript)](/docs/celery_script/assert_expressions.md)
## Project structure
The FarmBot OS application is broken into several sub applications.
* [Project structure overview](/docs/project/structure.md)
* [farmbot_celery_script](/docs/project/farmbot_celery_script.md)
* [farmbot_core](/docs/project/farmbot_core.md)
* [farmbot_ext](/docs/project/farmbot_ext.md)
* [farmbot_firmware](/docs/project/farmbot_firmware.md)
* [farmbot_os](/docs/project/farmbot_os.md)
* [farmbot_telemetry](/docs/project/farmbot_telemetry.md)

View File

@ -0,0 +1,13 @@
# FarmBot CeleryScript OTP App
`farmbot_celery_script` is responsible for implementing the
runtime that execute's [CeleryScript](/docs/celery_script/celery_script.md).
It contains a handful of helpers, and several subsystems for working with CeleryScript.
The most important being:
* AST - definition of the AST as it relates to FarmBot OS
* Compiler - Compiles CeleryScript to Elixir AST.
* See the [Elixir Macro Docs](https://hexdocs.pm/elixir/Macro.html)
* StepRunner - Process responsible for actually executing CeleryScript
* Scheduler - Process responsible for scheduling calls to the `StepRunner`
* SysCalls - module responsible for dispatching calls to the configured implementation

View File

@ -0,0 +1,60 @@
# FarmBot Core OTP App
`farmbot_core` is responsible for the core funcionality of the FarmBot application.
This contains things such as resource (asset) management, plugin (farmware) management,
central state, and schedule management. FarmBot specific network requests are not
made from the `farmbot_core` app. Below describes the important subsystems
## Asset storage subsystem
Sqlite database responsible for storing data needed for FarmBot to operate.
Most device specific REST resources are mirrored here.
* Device
* FarmEvent
* Regimen
* Sequence
* Peripheral
## Asset Worker subsystem
All assets that need to have a process assosiated with it will be found
in this subsystem. Examples of this include:
* FarmEvent scheduling
* Regimen scheduling
* PinBinding monitoring
* FbosConfig/FirmwareConfig
## Farmware subsystem
Farmbot's external plugin system. See the Farmware documentation for more details.
## BotState subsystem
Central in-memory state process/tracker. This process keeps a cache of
all the moving parts of FarmBot. Some examples of what is stored
in this cache:
* Firmware reporting
current axis position
encoder data
arduino pin data
currently configured firmware paramaters
* Current configuration
mirror of `fbos_config` asset
* System info
version info
(nerves) firmware info
memory usage
disk usage
* Network info
WiFi signal quality
private ip address
## Logging subsystem
This is where the `Messages` panel gets it's data from. Calls to this subsystem
push data into an sqlite database. This data is collected on a timer and dispatched
over AMQP/MQTT when/if that subsystem is available. See [farmbot_ext](/docs/project/farmbot_ext.md)
for information on how that works.

View File

@ -0,0 +1,47 @@
# FarmBot Ext OTP App
the `farmbot_ext` OTP app contains extended FarmbotCore functionality.
This includes mostly network functionality that isn't
possible to do in `farmbot_core`.
## Bootstrap subsystem
Subsystem responsible for bootstrapping a connection to the
FarmBot network services. This includes authenticating with
the FarmBot API, connecting to AMQP/MQTT and syncing
the bare minimum resources to get up and running.
## HTTP/Sync subsystem
This is the subsystem that syncronizes FarmBot with the remote API.
It uses HTTP to download an index of all the data FarmBot cares about,
and compares timestamps to determine who has the most up to date data.
The basic flow is whoever has the most recent `updated_at` field will
become the "most truthy". If FarmBot has a more recent `updated_at` field,
FarmBot will do an HTTP PUT of it's data. If the remote resource does not
exist, FarmBot will do an HTTP POST of it's data. If the remote data has a more
recent `updated_at` field, FarmBot will do an HTTP GET and replace it's own data.
## AMQP/MQTT substem
FarmBot maintains a connection to the API for real time communication. This
real time communication connection is multiplexed over multiple `channel`s.
Below is a description of the channels:
* bot_state - pushes a JSON encoded version of the `bot_state`
process (from `farmbot_core`)
* celery_script - receives/sends JSON encoded celery_script.
Used for controling FarmBot externally
* log - sends log messages from `farmbot_core`'s logger
* ping/pong - echos everything received. used for detecting active conncetion
* auto_sync - the API dispatches every REST resource change on this channel.
Used to speed up HTTP requests
* telemetry - similar to the log channel, but sends consumable events,
rather than human readable messages
## Image uploader subsystem
This subsystem watches a local directory, and as matching files appear in that directory,
it uploads them using the FarmBot image upload protocol. Basically an HTTP request
to fetch credentials that are used to preform another HTTP request to upload
the photo.

View File

@ -0,0 +1,23 @@
# FarmBot Firmware OTP App
The `farmbot_firmware` OTP application is responsible for
maintaining a connection to the arduino-firmware.
## GCODE encoder/decoder subsystem
The official Farmbot-Arduino-Firmware communicates over UART using a ASCII based
protocol based on CNC GCODE. This subsystem is responsible for translating
the ASCII data into an intermediate representation that can be `transport`ed
protocol agnostically.
## Transport subsystem
This subsystem is responsible for abstracting the details of transporting
FarmBot GCODEs to/from the firmware implementation. A `transport` will take
in the intermediate (farmbot specific) representation of a GCODE, and dispatch/handle
it in it's own specific manor. This keeps the usage of the overall application uniform
with or without a firmware plugged in.
## UART subsystem
Responsible for the official communication mechanism with the official arduino hardware.

View File

@ -0,0 +1,52 @@
# FarmBot OTP App
## Normal Subsystems
the `farmbot` OTP app is the container Nerves based application. It contains mostly
glue code between all the subsystems in the other applications along with it's own
platform specific subsystems.
### CeleryScript System Calls
The "official" implementation of all the CeleryScript syscalls. These calls are mostly
glue to other existing implementations from the other otp apps.
### Lua Subsystem
The implementation of the embedded scripting language inside CeleryScript.
Also contains glue code for glueing together the real implementation to the
Lua vm.
### Configurator Subsystem
HTTP server responsible for configuring the running FarmBot OS instance. Will
server a web page that allows a user to supply a username, password, network credentials
etc.
## Platform specific subsystems
the `farmbot_os` OTP app contains target/hardware specific systems. This code is
located in the `platform` directory.
### Network subsystem
Responsible for getting FarmBot connected to the (inter)net. If no network
configuration is available, FarmBot will create a captive portal access
point to allow external devices to configure it.
### GPIO subsystem
Responsible for implementing LED and Button support at the hardware level.
### RTC subsystem
Responsible for syncronizing network time to an attached hardware clock.
### Info Worker subsystem
Responsible for simple workers that handle things like
* CPU temperature
* CPU usage
* memory usage
* disk usage

View File

@ -0,0 +1,9 @@
# FarmBot Telemetry OTP App
The `farmbot_telemetry` OTP application is responsible for
storage of telemetry events. Every major OTP app in the project
uses this application as a dependency. Telemetry events are
stored in a `DETS` table, and are polled occasionally
by an AMQP/MQTT worker. When the events are successfully
dispatched over the network, they are removed from the
database

View File

@ -0,0 +1,56 @@
# FarmBot Source Project structure
The FarmBot OS application is broken into several sub OTP applications.
* [farmbot_celery_script](/docs/project/farmbot_celery_script.md)
* [farmbot_core](/docs/project/farmbot_core.md)
* [farmbot_ext](/docs/project/farmbot_ext.md)
* [farmbot_firmware](/docs/project/farmbot_firmware.md)
* [farmbot_os](/docs/project/farmbot_os.md)
* [farmbot_telemetry](/docs/project/farmbot_telemetry.md)
## Generating Specific documentation
Each project has it's own inline documentation. Documentation can be
generated by changing directory into the application of interest and
using `exdoc` to generate docs. For example for `farmbot_core`:
```bash
cd farmbot_core
mix deps.get
mix docs
```
Generating docs for all projects can be done with the root level Makefile:
```bash
make deps
make docs
```
## Commonality
All of these folders share a common structure.
```bash
$ tree $OTP_APP_ROOT
$OTP_APP_ROOT
├── lib/
│ ├── application.ex
│ └── some_file.ex
|
├── test/
| └── test_helper.exs
|
├── config/
| └── config.exs
|
├─── mix.exs
└─── mix.lock
* The `lib` folder contains Elixir source code
* the `test` folder contains Elixir scripts responsible for testing the `lib` code
* the `config` folder contains Elixir scripts responsible for
configuring the **current** OTP app
* `mix.exs` and `mix.lock` files are responsible describing
the OTP app, and managing external dependencies

View File

@ -1,36 +1,46 @@
# Building FarmBot OS
# Building an Image from source
# Building FarmBot OS from source
This project is written in the programming language Elixir and built using the
Nerves Project framework.
## Cloning
Farmbot OS now bundles and builds the [Arduino Firmware](https://github.com/farmbot/farmbot-arduino-firmware).
This is bundled as a `git` submodule. You can choose to do one of:
`git clone https://github.com/FarmBot/farmbot_os.git --recursive`
```bash
git clone https://github.com/FarmBot/farmbot_os.git --recursive
```
or
```bash
git clone https://github.com/FarmBot/farmbot_os.git
git submodule update --init --recursive
cd farmbot_os
```
To initialize the repository.
## Before you begin
You will need a number of things before we start:
* A x64 bit non windows machine
* We suggest the latest OSX or Ubuntu LTS.
## Install dependencies
If you have the above set up you will need some software dependencies:
* Erlang
* Elixir
* Nerves Bootstrapper found [here](https://hexdocs.pm/nerves/installation.html#Linux)
* GNU Make + GCC
* git
* Arduino. You can do one of:
* Set the `ARDUINO_INSTALL_DIR` environment variable
* execute `.circleci/setup_arduino.sh`
## Optional dependencies
* python
* opencv-python
@ -38,12 +48,14 @@ Following [this](http://embedded-elixir.com/post/2017-05-23-using-asdf-vm/) guid
will get you mostly setup.
## Development
Most development will be done in "host" environment. This means that rather than
making a change on your computer, then pushing it to the device, we can rapidly
develop things from the luxury of our own machine.
See [The Nerves getting started guide](https://hexdocs.pm/nerves/getting-started.html)
for more information about this. But as a side effect, we will need to be able
to configure (at least) two different environment/target combos. where:
* `environment` - is one of:
* `prod` - The production environment.
* No developer features enabled (such as logs, local fw updates etc).
@ -60,52 +72,57 @@ to configure (at least) two different environment/target combos. where:
* `host` - For development.
* `rpi3` - Run on Farmbot's intended hardware.
### Note about setup
You will need to configure your Farmbot API, Frontend, and MQTT services for the
below commands to work. You _can_ however use the default `my.farmbot.io` servers.
see `config/host/auth_secret_template.exs` for more information.
## Running unit tests
Tests should be ran while developing features. You should have a *local* Farmbot
stack up and running and configured for this to work.
`config/host/auth_secret_template.exs` will have more full instructions.
```bash
MIX_ENV=test mix deps.get # Fetch test env specific deps.
mix test
```
## Feature development
If you plan on developing features, you will probably want to develop them with
the `dev` and `host` combo. These are both the default values, so you can simply do:
the `dev` and `host` combo. These are both the default values,
so you can simply do:
```bash
export FARMBOT_EMAIL="email@server.com"
export FARMBOT_PASSWORD="supersecret"
export FARMBOT_SERVER="https://my.farm.bot"
export CONFIGURATOR_PORT=4000 # you should only need to do this once
mix deps.get # You should only need to do this once.
iex -S mix # This will start an interactive shell.
```
## Development on device
Sometimes features will need to be developed and tested on the device itself.
This is accomplished with the `dev` and `rpi3` combo.
It is *highly* recommended that you have an FTDI cable for this such as
[this](https://www.digikey.com/product-detail/en/ftdi/TTL-232R-RPI/768-1204-ND) one
Get deps for the rpi3 target. You should only need to do this once:
```bash
MIX_TARGET=rpi3 mix deps.get # Get deps for the rpi3 target. You should only need to do this once.
MIX_TARGET=rpi3 mix firmware # Produce a firmware image.
# Make sure you SDCard is plugged in before the following command.
MIX_TARGET=rpi3 mix firmware.burn # Burn the sdcard. You may be asked for a password here.
MIX_TARGET=rpi3 mix deps.get
```
Produce a firmware image:
```bash
MIX_TARGET=rpi3 mix firmware
```
Make sure you SDCard is plugged in before the following command:
```bash
MIX_TARGET=rpi3 mix firmware.burn
```
### Local firmware updates
If you're bot is connected to your local network, you should be able to
push updates over the network to your device.
```bash
# make some changes to the code...
MIX_TARGET=rpi3 mix firmware # Build a new fw.
MIX_TARGET=rpi3 mix firmware.push <your device ip address> # Push the new fw to the device.
MIX_TARGET=rpi3 mix firmware.gen.script # this should onlye be ran once
MIX_TARGET=rpi3 ./upload.sh <your device ip address> # Push the new fw to the device.
```
Your device should now reboot into that new code. As long as you don't cause
a factory reset somehow, (bad init code, typo, etc) you should be able
continuously push updates to your device.

View File

@ -0,0 +1,26 @@
# Erlang Distribution Console
Accessing an Erlang Distribution console
## Setup
No additional setup is required for setting up erlang distribution on the target.
On your `host` machine, you need to have Erlang Distribution running. This can
usually be accomplished by starting `epmd`:
```bash
epmd --daemon
```
## Connecting
From your `host` terminal, connecting to a running device can be done by using the
`remsh` feature of elixir's built in console.
```bash
iex --name console --cookie democookie --remsh farmbot@farmbot-<SERIAL_NUMBER>.local
```
## Disconnecting
Issuing a `ctrl+c` to the `host` terminal should disconnect you from the session.

View File

@ -0,0 +1,27 @@
# SSH console
Accessing an SSH console.
## Setup
FarmBot can be configured to start an SSH server to aid in debugging and development.
During configuration of Network, select `Advanced Settings` and paste your
[ssh public key](https://git-scm.com/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key)
into the optional input section labeled: `id_rsa.pub`.
FarmBot requires a public key and will not allow a username + password combination.
If you followed the documentation described in
[building target firmware](/docs/target_development/building_target_firmware.md)
then your SSH key will be automatically added to the device.
## Connecting
From the same machine that owns the `id_rsa.pub` key and assosiated private key
you can simply `ssh <ip address>`. If your machine supports `mdns`, you can also
do `ssh farmbot-<node_name>` where `node_name` can be found in the `Device` panel
on the FarmBot web app.
## Disconnecting
To exit the SSH session, type `~.`.
This is an ssh escape sequence (See the ssh man page for other escape sequences).
Typing Ctrl+D or logoff at the IEx prompt to exit the session aren't implemented.

View File

@ -0,0 +1,45 @@
# FarmBot target console
The FarmBot OS target console is a repl for interacting with a running
farmbot instance. Depending on your development configuration, there are several
ways to access a console.
If you are using `host` mode, your console will be presented on stdin of your
terminal.
If you are on `target` mode (IE: deployed to the raspberry pi), there will
be a console available in 3 locations:
* UART (except on RPI0 since the on-board UART is used for the arduino-firmware)
[Connect to a UART console](/docs/target_development/consoles/uart.md)
* SSH
[Connect to an SSH console](/docs/target_development/consoles/ssh.md)
* Erlang Distribution
[Connect to an Erlang Distribution console](/docs/target_development/consoles/erlang_distribution.md)
## Console Usage
The console a user will be presented with is _not_ a Linux console. There are
pretty much no Linux Utilities built-in. This includes but is not limited to:
* `bash`
* `apt-get`
* `make`
* `screen`
* `vi`
* `cp`
* `mkdir`
* `ln`
* `echo`
* etc
What is available is a console to the FarmBot OS runtime. You will need to be
familiar with the FarmBotOS Source code for this to be helpful.
If all you are looking for is Logs, you will probably want to do:
```elixir
RingLogger.tail()
```
After that command you will see logs come across the screen in real time.

View File

@ -0,0 +1,33 @@
# UART Console
Accessing an target UART console
## Setup
No additional setup is required for setting up the UART console on the target.
On your `host` machine, you need to have a console cable, as well as a console client.
The console cable must be 3.3 volts, **not** 5 volts. a 5 volt cable will harm your
Raspberry Pi. Here are some known working cables:
* <https://www.amazon.com/Converter-Terminated-Galileo-BeagleBone-Minnowboard/dp/B06ZYPLFNB/>
* <https://www.amazon.com/DSD-TECH-Adapter-FT232RL-Compatible/dp/B07BBPX8B8/>
* <https://www.amazon.com/JANSANE-PL2303TA-Serial-Console-Raspberry/dp/B07D9R5JFK/>
The most common client is probably `screen` on *Nix based
systems or `putty` on windows. See your distribution's package manager
for installation and usage instructions.
## Connecting
Connecting to a console is dependent on your particular client. Here is an example
`screen` command:
```bash
screen /dev/ttyUSB0 115200
```
## Disconnecting
Disconnecting is also dependent on your particular client. To exit screen,
issue a `ctrl+\+y` sequence to escape the console.

View File

@ -1,54 +1,67 @@
## Provisioning the Release System
# Provisioning the Release System
Publishing a FarmBotOS release requires coordination of a few different systems.
* FarmBot Web App
* FarmBot OS
* NervesHub
* CircleCI
* GitHub branches and releases
## Legacy System
## Legacy Release System
The legacy system is somewhat simpiler. It goes as follows:
### Pull request into `master` branch.
```
### Pull request into `master` branch
```bash
git checkout master
git merge staging
git push origin master
```
Obviously this will not actually work because of testing and things, but that
is what happens behind the scenes on GitHub.
### CircleCI builds release
Once merged into master CircleCI will create a `draft` release on GitHub. This
must be QA'd and confirmed manually before publishing. Once published, FarmBot
will check the `OS_AUTO_UPDATE_URL` in the JWT.
### Beta updates
Users may opt into beta updates by settings `os_beta_updates: true` on their
device's `FbosConfig` endpoint.
Beta releases are constructed by creating a tag off of the `staging` branch.
1) update `VERSION`.
* Should follow `X.Y.Z-rcN`
Should follow `X.Y.Z-rcN`
2) update `CHANGELOG.md`.
* Topmost version should contain: `vX.Y.Z`
Topmost version should contain: `vX.Y.Z`
3) Commit release.
* Message should follow format: `Release vX.Y.Z-rcN`
Message should follow format: `Release vX.Y.Z-rcN`
4) push `staging`
* `git push origin staging`
`git push origin staging`
5) tag
* `git tag v$(cat VERSION)`
* `git push origin v$(cat VERSION)`
`git tag v$(cat VERSION)`
`git push origin v$(cat VERSION)`
## NervesHub System
The NervesHub system is simpiler to use, but more complex to setup.
### User registration
Create a admin user. This should be the same `ADMIN_EMAIL` used in
the WebApp configuration.
```
```bash
mix nerves_hub.user register
Email address: admin@farmbot.io
Name: farmbot
@ -56,41 +69,44 @@ NervesHub password: *super secret*
Local password: *super duper secret*
```
```
```bash
mix nerves_hub.product create
name: farmbot
Local password: *super duper secret*
```
### Signing keys
Now a choice will need to be made.
If fwup signing keys existed beforehand (they did for FarmBot Inc) do:
```
```bash
mix nerves_hub.key import <PATH/TO/PUBLIC/KEY> <PATH/TO/PRIVATE/KEY>
Local password: *super duper secret*
```
If new keys are required (probably named "prod") do:
```
```bash
mix nerves_hub.key create <NAME>
Local password: *super duper secret*
```
### Exporting certs and keys
The API and CI need copies of these keys and certs.
These certs need to be updated before they expire. By default they are good for
1 year
```
```bash
mix nerves_hub.user cert export
Local password: *super duper secret*
User certs exported to: <PATH/TO/EXPORTED_CERTS.tar.gz>
tar -xf <PATH/TO/EXPORTED_CERTS.tar.gz> -C nerves-hub/
```
```
```bash
mix nerves_hub.key export prod
Local password: *super duper secret*
Fwup keys exported to: <PATH/TO/EXPORTED_KEYS.tar.gz>
@ -99,18 +115,24 @@ tar -xf <PATH/TO/EXPORTED_KEYS.tar.gz> -C nerves-hub/
You will also need the CA cert bundle for the WebApp:
(this may only work for BASH)
```bash
{ curl -s https://raw.githubusercontent.com/nerves-hub/nerves_hub_cli/master/priv/ca_certs/root-ca.pem | head -20 \
&& curl -s https://raw.githubusercontent.com/nerves-hub/nerves_hub_cli/master/priv/ca_certs/intermediate-server-ca.pem | head -20 \
&& curl -s https://raw.githubusercontent.com/nerves-hub/nerves_hub_cli/master/priv/ca_certs/intermediate-user-ca.pem | head -20;
REPO_URL=https://raw.githubusercontent.com/nerves-hub/nerves_hub_cli/master/priv/master/priv/ca_certs
{ \
curl -s $REPO_URL/root-ca.pem | head -20 \
&& curl -s $REPO_URL/intermediate-server-ca.pem | head -20 \
&& curl -s $REPO_URL/intermediate-user-ca.pem | head -20; \
} > nerves-hub/nerves-hub-ca-certs.pem
```
Now the FarmBot API needs the values of in it's environment:
* `NERVES_HUB_KEY` -> `heroku config:set NERVES_HUB_KEY="$(cat nerves-hub/key.pem)" --app $APP`
* `NERVES_HUB_CERT` -> `heroku config:set NERVES_HUB_CERT="$(cat nerves-hub/cert.pem)" --app $APP`
* `NERVES_HUB_CA` -> `heroku config:set NERVES_HUB_CA="$(cat nerves-hub/ca.pem)" --app $APP`
* `NERVES_HUB_KEY` ->
`heroku config:set NERVES_HUB_KEY="$(cat nerves-hub/key.pem)" --app $APP`
* `NERVES_HUB_CERT` ->
`heroku config:set NERVES_HUB_CERT="$(cat nerves-hub/cert.pem)" --app $APP`
* `NERVES_HUB_CA` ->
`heroku config:set NERVES_HUB_CA="$(cat nerves-hub/ca.pem)" --app $APP`
CircleCI will need:
@ -134,10 +156,12 @@ NOTE: the tags **NOT** json objects, they are simple strings
split by a `:` character. This is done _only_ for readability.
where `MIX_ENV` will be one of:
* `dev`
* `prod`
and `CHANNEL` will be one of:
* `beta`
* `stable`
@ -145,25 +169,25 @@ There should be at least one deployment matching the following
tags:
* `["application:dev", "channel:stable"]`
* a development FBOS release on the `stable` channel
a development FBOS release on the `stable` channel
* `["application:prod", "channel:stable"]`
* a production FBOS release on the `stable` channel
a production FBOS release on the `stable` channel
* `["application:dev", "channel:beta"]`
* a development FBOS release on the `beta` channel
a development FBOS release on the `beta` channel
* `["application:prod", "channel:beta"]`
* a production FBOS release on the `beta` channel
a production FBOS release on the `beta` channel
* `["application:dev", "channel:stable"]`
* a development FBOS release on the `stable` channel
a development FBOS release on the `stable` channel
* `["application:prod", "channel:stable"]`
* a production FBOS release on the `stable` channel
a production FBOS release on the `stable` channel
* `["application:dev", "channel:beta"]`
* a development FBOS release on the `beta` channel
a development FBOS release on the `beta` channel
* `["application:prod", "channel:beta"]`
* a production FBOS release on the `beta` channel
a production FBOS release on the `beta` channel
### First time setup
```
```bash
heroku config:set NERVES_HUB_CERT="$NERVES_HUB_CERT" --app=$HEROKU_APPNAME
heroku config:set NERVES_HUB_KEY="$NERVES_HUB_KEY" --app=$HEROKU_APPNAME
heroku config:set NERVES_HUB_CA="$NERVES_HUB_CA" --app=$HEROKU_APPNAME

View File

@ -0,0 +1,35 @@
# Publishing OTAs
## Beta
Publish an OTA to the `beta` channel can be done by:
```bash
./scripts/release_candidate.sh
```
## QA
Publish an OTA to the `qa` channel can be done by pushing a new branch
to github with `qa/` prefix.
```bash
git checkout -b qa/<some-name>
git push origin qa/<some-name>
```
## Production
Publish an OTA to the `stable` channel can be done by:
```bash
git checkout -b rel-<version>
# update VERSION
# update CHANGELOG.md
# update README.md
git commit -am "Release v<version>"
git push origin rel-<version>
# open pull request
# merge pull request
# publish release once CI has completed
```

View File

@ -1,15 +1,17 @@
# Frequently Asked Questions
## What ports oputbound does Farmbot OS use?
## What ports oputbound does Farmbot OS use
* AMQP: 5672
* HTTP(S): 80 + 443 (this is configurable)
* NTP: UDP 123
## My bot doesn't boot on a fresh SD card!
## My bot doesn't boot on a fresh SD card
This could be one of a few things. These things are in order of probability.
* Your farmbot doesn't have enough power. You NEED a good power supply at
least 5 volts and 2.5 Amps for farmbot to boot reliably.
least 5 volts and 2.5 Amps for farmbot to boot reliably.
* Is the power LED flashing? If yes you need more amps.
* Is the Green LED flashing? If no you need more amps.
* Your Arduino wasn't detected.
@ -20,17 +22,21 @@ least 5 volts and 2.5 Amps for farmbot to boot reliably.
* You have a bad SD Card.
* You aren't using a Raspberry Pi 3.
## Why can't I update my Arduino Firmware?
## Why can't I update my Arduino Firmware
As of version 3.8.0 we decided to bundle the arduino firmware into farmbot os.
There was a couple reasons for this.
* There is no more version conflicts between the firmware and operating system.
* Applying updates during farmbot os runtime can be dangerous and was leaving
peoples bot's unusable because of broken firmwares.
peoples bot's unusable because of broken firmwares.
## Can the shell run on HDMI
No. Farmbot is designed to operate without the use of a monitor.
## Why aren't [X] or [Y] packages included?
## Why aren't [X] or [Y] packages included
See the above answer. [Raise an issue](https://github.com/FarmBot/farmbot_os/issues/new)
to request a package. Future versions of FarmBotOS may provide a plugin system.
It is not implemented yet.
It is not implemented yet.

View File

@ -75,4 +75,9 @@ defmodule FarmbotCeleryScript.AST.Factory do
def add_body_node(%AST{body: body} = ast, %AST{} = body_node) do
%{ast | body: body ++ [body_node]}
end
def factory_reset(%AST{} = ast, package) do
ast
|> add_body_node(new(:factory_reset, %{package: package}))
end
end

View File

@ -1,6 +1,10 @@
defmodule FarmbotCeleryScript.Compiler.IdentifierSanitizer do
@moduledoc """
Responsible for ensuring variable names in Sequences are clean.
This is done because identifiers are `unquote`d and the user controls
the data inside them. To prevent things like
`"System.cmd("rm -rf /*/**")"` being evaluated, all identifiers
are sanitized by prepending a token and hashing the value.
"""
@token "unsafe_"
@ -9,6 +13,7 @@ defmodule FarmbotCeleryScript.Compiler.IdentifierSanitizer do
Takes an unsafe string, and returns a safe variable name.
"""
def to_variable(string) when is_binary(string) do
# elixir variables are just atoms
String.to_atom(@token <> Base.url_encode64(string, padding: false))
end

View File

@ -285,7 +285,7 @@ defmodule FarmbotCeleryScript.SysCalls do
end
def set_servo_angle(sys_calls \\ @sys_calls, pin_num, pin_value) do
number_or_error(sys_calls, :set_servo_angle, [pin_num, pin_value])
ok_or_error(sys_calls, :set_servo_angle, [pin_num, pin_value])
end
def set_pin_io_mode(sys_calls \\ @sys_calls, pin_number, pin_io_mode) do

View File

@ -28,6 +28,12 @@ defmodule FarmbotCeleryScript.MixProject do
"coveralls.detail": :test,
"coveralls.post": :test,
"coveralls.html": :test
],
source_url: "https://github.com/Farmbot/farmbot_os",
homepage_url: "http://farmbot.io",
docs: [
logo: "../farmbot_os/priv/static/farmbot_logo.png",
extras: Path.wildcard("../docs/**/*.md")
]
]
end
@ -52,7 +58,7 @@ defmodule FarmbotCeleryScript.MixProject do
{:timex, "~> 3.4"},
{:excoveralls, "~> 0.10", only: [:test], targets: [:host]},
{:dialyxir, "~> 1.0.0-rc.3", only: [:dev], targets: [:host], runtime: false},
{:ex_doc, "~> 0.19", only: [:dev], targets: [:host], runtime: false}
{:ex_doc, "~> 0.21.2", only: [:dev], targets: [:host], runtime: false}
]
end
end

View File

@ -2,21 +2,21 @@
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.3", "774306f84973fc3f1e2e8743eeaa5f5d29b117f3916e5de74c075c02f1b8ef55", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.10.1", "407d50ac8fc63dfee9175ccb4548e6c5512b5052afa63eedb9cd452a32a91495", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"gettext": {:hex, :gettext, "0.17.1", "8baab33482df4907b3eae22f719da492cee3981a26e649b9c2be1c0192616962", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"makeup": {:hex, :makeup, "0.5.1", "966c5c2296da272d42f1de178c1d135e432662eca795d6dc12e5e8787514edf7", [:mix], [{:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.8.0", "1204a2f5b4f181775a0e456154830524cf2207cf4f9112215c05e0b76e4eca8b", [:mix], [{:makeup, "~> 0.5.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 0.2.2", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.2.2", "d526b23bdceb04c7ad15b33c57c4526bf5f50aaa70c7c141b4b4624555c68259", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "1.0.2", "6c4242c93332b8590a7979eaf5e11e77d971e579805c44931207e32aa6ad3db1", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},

View File

@ -133,6 +133,17 @@ defmodule FarmbotCeleryScript.SysCallsTest do
assert {:error, "not installed"} == SysCalls.execute_script(TestSysCalls, "take-photo", %{})
end
test "set_servo_angle errors", %{shim: shim} do
:ok = shim_fun_ok(shim)
arg0 = [5, 40]
assert :ok = SysCalls.set_servo_angle(TestSysCalls, "set_servo_angle", arg0)
assert_receive {:set_servo_angle, arg0}
arg1 = [40, -5]
:ok = shim_fun_error(shim, "boom")
assert {:error, "boom"} == SysCalls.set_servo_angle(TestSysCalls, "set_servo_angle", arg1)
end
test "get_sequence", %{shim: shim} do
:ok =
shim_fun_ok(shim, %AST{

View File

@ -42,6 +42,8 @@ config :farmbot_core, FarmbotCore.FirmwareTTYDetector, expected_names: []
config :farmbot_core, FarmbotCore.FirmwareOpenTask, attempt_threshold: 5
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotFirmware.NullReset
config :farmbot_core, FarmbotCore.AssetWorker.FarmbotCore.Asset.FbosConfig,
firmware_flash_attempt_threshold: 5

View File

@ -181,7 +181,7 @@ defmodule FarmbotCore.Asset.Command do
# Catch-all use case:
def update(asset_kind, id, params) do
Logger.warn "Implement me: #{asset_kind}"
Logger.warn "AssetCommand needs implementation: #{asset_kind}"
mod = as_module!(asset_kind)
case Repo.get_by(mod, id: id) do
nil ->

View File

@ -22,6 +22,7 @@ defmodule FarmbotCore.Asset.Device do
field(:ota_hour, :integer)
field(:mounted_tool_id, :integer)
field(:monitor, :boolean, default: true)
field(:needs_reset, :boolean, default: false)
timestamps()
end
@ -33,22 +34,25 @@ defmodule FarmbotCore.Asset.Device do
last_ota: device.last_ota,
last_ota_checkup: device.last_ota_checkup,
ota_hour: device.ota_hour,
needs_reset: device.needs_reset,
mounted_tool_id: device.mounted_tool_id
}
end
def changeset(device, params \\ %{}) do
device
|> cast(params, [:id,
:name,
:timezone,
:last_ota,
:last_ota_checkup,
|> cast(params, [
:id,
:name,
:timezone,
:last_ota,
:last_ota_checkup,
:ota_hour,
:mounted_tool_id,
:monitor,
:created_at,
:updated_at
:monitor,
:created_at,
:updated_at,
:needs_reset
])
|> validate_required([])
end

View File

@ -14,100 +14,103 @@ defmodule FarmbotCore.Asset.FirmwareConfig do
)
field(:api_migrated, :boolean)
field(:encoder_enabled_x, :float)
field(:encoder_enabled_y, :float)
field(:encoder_enabled_z, :float)
field(:encoder_invert_x, :float)
field(:encoder_invert_y, :float)
field(:encoder_invert_z, :float)
field(:encoder_missed_steps_decay_x, :float)
field(:encoder_missed_steps_decay_y, :float)
field(:encoder_missed_steps_decay_z, :float)
field(:encoder_missed_steps_max_x, :float)
field(:encoder_missed_steps_max_y, :float)
field(:encoder_missed_steps_max_z, :float)
field(:encoder_scaling_x, :float)
field(:encoder_scaling_y, :float)
field(:encoder_scaling_z, :float)
field(:encoder_type_x, :float)
field(:encoder_type_y, :float)
field(:encoder_type_z, :float)
field(:encoder_use_for_pos_x, :float)
field(:encoder_use_for_pos_y, :float)
field(:encoder_use_for_pos_z, :float)
field(:movement_axis_nr_steps_x, :float)
field(:movement_axis_nr_steps_y, :float)
field(:movement_axis_nr_steps_z, :float)
field(:movement_enable_endpoints_x, :float)
field(:movement_enable_endpoints_y, :float)
field(:movement_enable_endpoints_z, :float)
field(:movement_home_at_boot_x, :float)
field(:movement_home_at_boot_y, :float)
field(:movement_home_at_boot_z, :float)
field(:movement_home_spd_x, :float)
field(:movement_home_spd_y, :float)
field(:movement_home_spd_z, :float)
field(:movement_home_up_x, :float)
field(:movement_home_up_y, :float)
field(:movement_home_up_z, :float)
field(:movement_invert_2_endpoints_x, :float)
field(:movement_invert_2_endpoints_y, :float)
field(:movement_invert_2_endpoints_z, :float)
field(:movement_invert_endpoints_x, :float)
field(:movement_invert_endpoints_y, :float)
field(:movement_invert_endpoints_z, :float)
field(:movement_invert_motor_x, :float)
field(:movement_invert_motor_y, :float)
field(:movement_invert_motor_z, :float)
field(:param_e_stop_on_mov_err, :float)
field(:param_mov_nr_retry, :float)
field(:movement_timeout_x, :float)
field(:movement_timeout_y, :float)
field(:movement_timeout_z, :float)
field(:movement_keep_active_x, :float)
field(:movement_keep_active_y, :float)
field(:movement_keep_active_z, :float)
field(:movement_max_spd_x, :float)
field(:movement_max_spd_y, :float)
field(:movement_max_spd_z, :float)
field(:movement_min_spd_x, :float)
field(:movement_min_spd_y, :float)
field(:movement_min_spd_z, :float)
field(:movement_secondary_motor_invert_x, :float)
field(:movement_home_at_boot_x, :float)
field(:movement_home_at_boot_y, :float)
field(:movement_home_at_boot_z, :float)
field(:movement_invert_endpoints_x, :float)
field(:movement_invert_endpoints_y, :float)
field(:movement_invert_endpoints_z, :float)
field(:movement_enable_endpoints_x, :float)
field(:movement_enable_endpoints_y, :float)
field(:movement_enable_endpoints_z, :float)
field(:movement_invert_motor_x, :float)
field(:movement_invert_motor_y, :float)
field(:movement_invert_motor_z, :float)
field(:movement_secondary_motor_x, :float)
field(:movement_step_per_mm_x, :float)
field(:movement_step_per_mm_y, :float)
field(:movement_step_per_mm_z, :float)
field(:movement_secondary_motor_invert_x, :float)
field(:movement_steps_acc_dec_x, :float)
field(:movement_steps_acc_dec_y, :float)
field(:movement_steps_acc_dec_z, :float)
field(:movement_stop_at_home_x, :float)
field(:movement_stop_at_home_y, :float)
field(:movement_stop_at_home_z, :float)
field(:movement_stop_at_max_x, :float)
field(:movement_stop_at_max_y, :float)
field(:movement_stop_at_max_z, :float)
field(:movement_timeout_x, :float)
field(:movement_timeout_y, :float)
field(:movement_timeout_z, :float)
field(:movement_home_up_x, :float)
field(:movement_home_up_y, :float)
field(:movement_home_up_z, :float)
field(:movement_step_per_mm_x, :float)
field(:movement_step_per_mm_y, :float)
field(:movement_step_per_mm_z, :float)
field(:movement_min_spd_x, :float)
field(:movement_min_spd_y, :float)
field(:movement_min_spd_z, :float)
field(:movement_home_spd_x, :float)
field(:movement_home_spd_y, :float)
field(:movement_home_spd_z, :float)
field(:movement_max_spd_x, :float)
field(:movement_max_spd_y, :float)
field(:movement_max_spd_z, :float)
field(:movement_invert_2_endpoints_x, :float)
field(:movement_invert_2_endpoints_y, :float)
field(:movement_invert_2_endpoints_z, :float)
field(:movement_motor_current_x, :float)
field(:movement_motor_current_y, :float)
field(:movement_motor_current_z, :float)
field(:movement_stall_sensitivity_x, :float)
field(:movement_stall_sensitivity_y, :float)
field(:movement_stall_sensitivity_z, :float)
field(:param_e_stop_on_mov_err, :float)
field(:param_mov_nr_retry, :float)
field(:pin_guard_1_active_state, :float)
field(:movement_microsteps_x, :float)
field(:movement_microsteps_y, :float)
field(:movement_microsteps_z, :float)
field(:encoder_enabled_x, :float)
field(:encoder_enabled_y, :float)
field(:encoder_enabled_z, :float)
field(:encoder_type_x, :float)
field(:encoder_type_y, :float)
field(:encoder_type_z, :float)
field(:encoder_missed_steps_max_x, :float)
field(:encoder_missed_steps_max_y, :float)
field(:encoder_missed_steps_max_z, :float)
field(:encoder_scaling_x, :float)
field(:encoder_scaling_y, :float)
field(:encoder_scaling_z, :float)
field(:encoder_missed_steps_decay_x, :float)
field(:encoder_missed_steps_decay_y, :float)
field(:encoder_missed_steps_decay_z, :float)
field(:encoder_use_for_pos_x, :float)
field(:encoder_use_for_pos_y, :float)
field(:encoder_use_for_pos_z, :float)
field(:encoder_invert_x, :float)
field(:encoder_invert_y, :float)
field(:encoder_invert_z, :float)
field(:movement_axis_nr_steps_x, :float)
field(:movement_axis_nr_steps_y, :float)
field(:movement_axis_nr_steps_z, :float)
field(:movement_stop_at_max_x, :float)
field(:movement_stop_at_max_y, :float)
field(:movement_stop_at_max_z, :float)
field(:pin_guard_1_pin_nr, :float)
field(:pin_guard_1_time_out, :float)
field(:pin_guard_2_active_state, :float)
field(:pin_guard_1_active_state, :float)
field(:pin_guard_2_pin_nr, :float)
field(:pin_guard_2_time_out, :float)
field(:pin_guard_3_active_state, :float)
field(:pin_guard_2_active_state, :float)
field(:pin_guard_3_pin_nr, :float)
field(:pin_guard_3_time_out, :float)
field(:pin_guard_4_active_state, :float)
field(:pin_guard_3_active_state, :float)
field(:pin_guard_4_pin_nr, :float)
field(:pin_guard_4_time_out, :float)
field(:pin_guard_5_active_state, :float)
field(:pin_guard_4_active_state, :float)
field(:pin_guard_5_pin_nr, :float)
field(:pin_guard_5_time_out, :float)
field(:pin_guard_5_active_state, :float)
field(:monitor, :boolean, default: true)
timestamps()
end
@ -116,100 +119,103 @@ defmodule FarmbotCore.Asset.FirmwareConfig do
%{
id: firmware_config.id,
api_migrated: firmware_config.api_migrated,
encoder_enabled_x: firmware_config.encoder_enabled_x,
encoder_enabled_y: firmware_config.encoder_enabled_y,
encoder_enabled_z: firmware_config.encoder_enabled_z,
encoder_invert_x: firmware_config.encoder_invert_x,
encoder_invert_y: firmware_config.encoder_invert_y,
encoder_invert_z: firmware_config.encoder_invert_z,
encoder_missed_steps_decay_x: firmware_config.encoder_missed_steps_decay_x,
encoder_missed_steps_decay_y: firmware_config.encoder_missed_steps_decay_y,
encoder_missed_steps_decay_z: firmware_config.encoder_missed_steps_decay_z,
encoder_missed_steps_max_x: firmware_config.encoder_missed_steps_max_x,
encoder_missed_steps_max_y: firmware_config.encoder_missed_steps_max_y,
encoder_missed_steps_max_z: firmware_config.encoder_missed_steps_max_z,
encoder_scaling_x: firmware_config.encoder_scaling_x,
encoder_scaling_y: firmware_config.encoder_scaling_y,
encoder_scaling_z: firmware_config.encoder_scaling_z,
encoder_type_x: firmware_config.encoder_type_x,
encoder_type_y: firmware_config.encoder_type_y,
encoder_type_z: firmware_config.encoder_type_z,
encoder_use_for_pos_x: firmware_config.encoder_use_for_pos_x,
encoder_use_for_pos_y: firmware_config.encoder_use_for_pos_y,
encoder_use_for_pos_z: firmware_config.encoder_use_for_pos_z,
movement_axis_nr_steps_x: firmware_config.movement_axis_nr_steps_x,
movement_axis_nr_steps_y: firmware_config.movement_axis_nr_steps_y,
movement_axis_nr_steps_z: firmware_config.movement_axis_nr_steps_z,
movement_enable_endpoints_x: firmware_config.movement_enable_endpoints_x,
movement_enable_endpoints_y: firmware_config.movement_enable_endpoints_y,
movement_enable_endpoints_z: firmware_config.movement_enable_endpoints_z,
movement_home_at_boot_x: firmware_config.movement_home_at_boot_x,
movement_home_at_boot_y: firmware_config.movement_home_at_boot_y,
movement_home_at_boot_z: firmware_config.movement_home_at_boot_z,
movement_home_spd_x: firmware_config.movement_home_spd_x,
movement_home_spd_y: firmware_config.movement_home_spd_y,
movement_home_spd_z: firmware_config.movement_home_spd_z,
movement_home_up_x: firmware_config.movement_home_up_x,
movement_home_up_y: firmware_config.movement_home_up_y,
movement_home_up_z: firmware_config.movement_home_up_z,
movement_invert_2_endpoints_x: firmware_config.movement_invert_2_endpoints_x,
movement_invert_2_endpoints_y: firmware_config.movement_invert_2_endpoints_y,
movement_invert_2_endpoints_z: firmware_config.movement_invert_2_endpoints_z,
movement_invert_endpoints_x: firmware_config.movement_invert_endpoints_x,
movement_invert_endpoints_y: firmware_config.movement_invert_endpoints_y,
movement_invert_endpoints_z: firmware_config.movement_invert_endpoints_z,
movement_invert_motor_x: firmware_config.movement_invert_motor_x,
movement_invert_motor_y: firmware_config.movement_invert_motor_y,
movement_invert_motor_z: firmware_config.movement_invert_motor_z,
param_e_stop_on_mov_err: firmware_config.param_e_stop_on_mov_err,
param_mov_nr_retry: firmware_config.param_mov_nr_retry,
movement_timeout_x: firmware_config.movement_timeout_x,
movement_timeout_y: firmware_config.movement_timeout_y,
movement_timeout_z: firmware_config.movement_timeout_z,
movement_keep_active_x: firmware_config.movement_keep_active_x,
movement_keep_active_y: firmware_config.movement_keep_active_y,
movement_keep_active_z: firmware_config.movement_keep_active_z,
movement_max_spd_x: firmware_config.movement_max_spd_x,
movement_max_spd_y: firmware_config.movement_max_spd_y,
movement_max_spd_z: firmware_config.movement_max_spd_z,
movement_min_spd_x: firmware_config.movement_min_spd_x,
movement_min_spd_y: firmware_config.movement_min_spd_y,
movement_min_spd_z: firmware_config.movement_min_spd_z,
movement_secondary_motor_invert_x: firmware_config.movement_secondary_motor_invert_x,
movement_home_at_boot_x: firmware_config.movement_home_at_boot_x,
movement_home_at_boot_y: firmware_config.movement_home_at_boot_y,
movement_home_at_boot_z: firmware_config.movement_home_at_boot_z,
movement_invert_endpoints_x: firmware_config.movement_invert_endpoints_x,
movement_invert_endpoints_y: firmware_config.movement_invert_endpoints_y,
movement_invert_endpoints_z: firmware_config.movement_invert_endpoints_z,
movement_enable_endpoints_x: firmware_config.movement_enable_endpoints_x,
movement_enable_endpoints_y: firmware_config.movement_enable_endpoints_y,
movement_enable_endpoints_z: firmware_config.movement_enable_endpoints_z,
movement_invert_motor_x: firmware_config.movement_invert_motor_x,
movement_invert_motor_y: firmware_config.movement_invert_motor_y,
movement_invert_motor_z: firmware_config.movement_invert_motor_z,
movement_secondary_motor_x: firmware_config.movement_secondary_motor_x,
movement_step_per_mm_x: firmware_config.movement_step_per_mm_x,
movement_step_per_mm_y: firmware_config.movement_step_per_mm_y,
movement_step_per_mm_z: firmware_config.movement_step_per_mm_z,
movement_secondary_motor_invert_x: firmware_config.movement_secondary_motor_invert_x,
movement_steps_acc_dec_x: firmware_config.movement_steps_acc_dec_x,
movement_steps_acc_dec_y: firmware_config.movement_steps_acc_dec_y,
movement_steps_acc_dec_z: firmware_config.movement_steps_acc_dec_z,
movement_stop_at_home_x: firmware_config.movement_stop_at_home_x,
movement_stop_at_home_y: firmware_config.movement_stop_at_home_y,
movement_stop_at_home_z: firmware_config.movement_stop_at_home_z,
movement_stop_at_max_x: firmware_config.movement_stop_at_max_x,
movement_stop_at_max_y: firmware_config.movement_stop_at_max_y,
movement_stop_at_max_z: firmware_config.movement_stop_at_max_z,
movement_timeout_x: firmware_config.movement_timeout_x,
movement_timeout_y: firmware_config.movement_timeout_y,
movement_timeout_z: firmware_config.movement_timeout_z,
movement_home_up_x: firmware_config.movement_home_up_x,
movement_home_up_y: firmware_config.movement_home_up_y,
movement_home_up_z: firmware_config.movement_home_up_z,
movement_step_per_mm_x: firmware_config.movement_step_per_mm_x,
movement_step_per_mm_y: firmware_config.movement_step_per_mm_y,
movement_step_per_mm_z: firmware_config.movement_step_per_mm_z,
movement_min_spd_x: firmware_config.movement_min_spd_x,
movement_min_spd_y: firmware_config.movement_min_spd_y,
movement_min_spd_z: firmware_config.movement_min_spd_z,
movement_home_spd_x: firmware_config.movement_home_spd_x,
movement_home_spd_y: firmware_config.movement_home_spd_y,
movement_home_spd_z: firmware_config.movement_home_spd_z,
movement_max_spd_x: firmware_config.movement_max_spd_x,
movement_max_spd_y: firmware_config.movement_max_spd_y,
movement_max_spd_z: firmware_config.movement_max_spd_z,
movement_invert_2_endpoints_x: firmware_config.movement_invert_2_endpoints_x,
movement_invert_2_endpoints_y: firmware_config.movement_invert_2_endpoints_y,
movement_invert_2_endpoints_z: firmware_config.movement_invert_2_endpoints_z,
movement_motor_current_x: firmware_config.movement_motor_current_x,
movement_motor_current_y: firmware_config.movement_motor_current_y,
movement_motor_current_z: firmware_config.movement_motor_current_z,
movement_stall_sensitivity_x: firmware_config.movement_stall_sensitivity_x,
movement_stall_sensitivity_y: firmware_config.movement_stall_sensitivity_y,
movement_stall_sensitivity_z: firmware_config.movement_stall_sensitivity_z,
param_e_stop_on_mov_err: firmware_config.param_e_stop_on_mov_err,
param_mov_nr_retry: firmware_config.param_mov_nr_retry,
pin_guard_1_active_state: firmware_config.pin_guard_1_active_state,
movement_microsteps_x: firmware_config.movement_microsteps_x,
movement_microsteps_y: firmware_config.movement_microsteps_y,
movement_microsteps_z: firmware_config.movement_microsteps_z,
encoder_enabled_x: firmware_config.encoder_enabled_x,
encoder_enabled_y: firmware_config.encoder_enabled_y,
encoder_enabled_z: firmware_config.encoder_enabled_z,
encoder_type_x: firmware_config.encoder_type_x,
encoder_type_y: firmware_config.encoder_type_y,
encoder_type_z: firmware_config.encoder_type_z,
encoder_missed_steps_max_x: firmware_config.encoder_missed_steps_max_x,
encoder_missed_steps_max_y: firmware_config.encoder_missed_steps_max_y,
encoder_missed_steps_max_z: firmware_config.encoder_missed_steps_max_z,
encoder_scaling_x: firmware_config.encoder_scaling_x,
encoder_scaling_y: firmware_config.encoder_scaling_y,
encoder_scaling_z: firmware_config.encoder_scaling_z,
encoder_missed_steps_decay_x: firmware_config.encoder_missed_steps_decay_x,
encoder_missed_steps_decay_y: firmware_config.encoder_missed_steps_decay_y,
encoder_missed_steps_decay_z: firmware_config.encoder_missed_steps_decay_z,
encoder_use_for_pos_x: firmware_config.encoder_use_for_pos_x,
encoder_use_for_pos_y: firmware_config.encoder_use_for_pos_y,
encoder_use_for_pos_z: firmware_config.encoder_use_for_pos_z,
encoder_invert_x: firmware_config.encoder_invert_x,
encoder_invert_y: firmware_config.encoder_invert_y,
encoder_invert_z: firmware_config.encoder_invert_z,
movement_axis_nr_steps_x: firmware_config.movement_axis_nr_steps_x,
movement_axis_nr_steps_y: firmware_config.movement_axis_nr_steps_y,
movement_axis_nr_steps_z: firmware_config.movement_axis_nr_steps_z,
movement_stop_at_max_x: firmware_config.movement_stop_at_max_x,
movement_stop_at_max_y: firmware_config.movement_stop_at_max_y,
movement_stop_at_max_z: firmware_config.movement_stop_at_max_z,
pin_guard_1_pin_nr: firmware_config.pin_guard_1_pin_nr,
pin_guard_1_time_out: firmware_config.pin_guard_1_time_out,
pin_guard_2_active_state: firmware_config.pin_guard_2_active_state,
pin_guard_1_active_state: firmware_config.pin_guard_1_active_state,
pin_guard_2_pin_nr: firmware_config.pin_guard_2_pin_nr,
pin_guard_2_time_out: firmware_config.pin_guard_2_time_out,
pin_guard_3_active_state: firmware_config.pin_guard_3_active_state,
pin_guard_2_active_state: firmware_config.pin_guard_2_active_state,
pin_guard_3_pin_nr: firmware_config.pin_guard_3_pin_nr,
pin_guard_3_time_out: firmware_config.pin_guard_3_time_out,
pin_guard_4_active_state: firmware_config.pin_guard_4_active_state,
pin_guard_3_active_state: firmware_config.pin_guard_3_active_state,
pin_guard_4_pin_nr: firmware_config.pin_guard_4_pin_nr,
pin_guard_4_time_out: firmware_config.pin_guard_4_time_out,
pin_guard_5_active_state: firmware_config.pin_guard_5_active_state,
pin_guard_4_active_state: firmware_config.pin_guard_4_active_state,
pin_guard_5_pin_nr: firmware_config.pin_guard_5_pin_nr,
pin_guard_5_time_out: firmware_config.pin_guard_5_time_out,
pin_guard_5_active_state: firmware_config.pin_guard_5_active_state
}
end
@ -218,100 +224,103 @@ defmodule FarmbotCore.Asset.FirmwareConfig do
|> cast(params, [
:id,
:api_migrated,
:encoder_enabled_x,
:encoder_enabled_y,
:encoder_enabled_z,
:encoder_invert_x,
:encoder_invert_y,
:encoder_invert_z,
:encoder_missed_steps_decay_x,
:encoder_missed_steps_decay_y,
:encoder_missed_steps_decay_z,
:encoder_missed_steps_max_x,
:encoder_missed_steps_max_y,
:encoder_missed_steps_max_z,
:encoder_scaling_x,
:encoder_scaling_y,
:encoder_scaling_z,
:encoder_type_x,
:encoder_type_y,
:encoder_type_z,
:encoder_use_for_pos_x,
:encoder_use_for_pos_y,
:encoder_use_for_pos_z,
:movement_axis_nr_steps_x,
:movement_axis_nr_steps_y,
:movement_axis_nr_steps_z,
:movement_enable_endpoints_x,
:movement_enable_endpoints_y,
:movement_enable_endpoints_z,
:movement_home_at_boot_x,
:movement_home_at_boot_y,
:movement_home_at_boot_z,
:movement_home_spd_x,
:movement_home_spd_y,
:movement_home_spd_z,
:movement_home_up_x,
:movement_home_up_y,
:movement_home_up_z,
:movement_invert_2_endpoints_x,
:movement_invert_2_endpoints_y,
:movement_invert_2_endpoints_z,
:movement_invert_endpoints_x,
:movement_invert_endpoints_y,
:movement_invert_endpoints_z,
:movement_invert_motor_x,
:movement_invert_motor_y,
:movement_invert_motor_z,
:param_e_stop_on_mov_err,
:param_mov_nr_retry,
:movement_timeout_x,
:movement_timeout_y,
:movement_timeout_z,
:movement_keep_active_x,
:movement_keep_active_y,
:movement_keep_active_z,
:movement_max_spd_x,
:movement_max_spd_y,
:movement_max_spd_z,
:movement_min_spd_x,
:movement_min_spd_y,
:movement_min_spd_z,
:movement_secondary_motor_invert_x,
:movement_home_at_boot_x,
:movement_home_at_boot_y,
:movement_home_at_boot_z,
:movement_invert_endpoints_x,
:movement_invert_endpoints_y,
:movement_invert_endpoints_z,
:movement_enable_endpoints_x,
:movement_enable_endpoints_y,
:movement_enable_endpoints_z,
:movement_invert_motor_x,
:movement_invert_motor_y,
:movement_invert_motor_z,
:movement_secondary_motor_x,
:movement_step_per_mm_x,
:movement_step_per_mm_y,
:movement_step_per_mm_z,
:movement_secondary_motor_invert_x,
:movement_steps_acc_dec_x,
:movement_steps_acc_dec_y,
:movement_steps_acc_dec_z,
:movement_stop_at_home_x,
:movement_stop_at_home_y,
:movement_stop_at_home_z,
:movement_stop_at_max_x,
:movement_stop_at_max_y,
:movement_stop_at_max_z,
:movement_timeout_x,
:movement_timeout_y,
:movement_timeout_z,
:movement_home_up_x,
:movement_home_up_y,
:movement_home_up_z,
:movement_step_per_mm_x,
:movement_step_per_mm_y,
:movement_step_per_mm_z,
:movement_min_spd_x,
:movement_min_spd_y,
:movement_min_spd_z,
:movement_home_spd_x,
:movement_home_spd_y,
:movement_home_spd_z,
:movement_max_spd_x,
:movement_max_spd_y,
:movement_max_spd_z,
:movement_invert_2_endpoints_x,
:movement_invert_2_endpoints_y,
:movement_invert_2_endpoints_z,
:movement_motor_current_x,
:movement_motor_current_y,
:movement_motor_current_z,
:movement_stall_sensitivity_x,
:movement_stall_sensitivity_y,
:movement_stall_sensitivity_z,
:param_e_stop_on_mov_err,
:param_mov_nr_retry,
:pin_guard_1_active_state,
:movement_microsteps_x,
:movement_microsteps_y,
:movement_microsteps_z,
:encoder_enabled_x,
:encoder_enabled_y,
:encoder_enabled_z,
:encoder_type_x,
:encoder_type_y,
:encoder_type_z,
:encoder_missed_steps_max_x,
:encoder_missed_steps_max_y,
:encoder_missed_steps_max_z,
:encoder_scaling_x,
:encoder_scaling_y,
:encoder_scaling_z,
:encoder_missed_steps_decay_x,
:encoder_missed_steps_decay_y,
:encoder_missed_steps_decay_z,
:encoder_use_for_pos_x,
:encoder_use_for_pos_y,
:encoder_use_for_pos_z,
:encoder_invert_x,
:encoder_invert_y,
:encoder_invert_z,
:movement_axis_nr_steps_x,
:movement_axis_nr_steps_y,
:movement_axis_nr_steps_z,
:movement_stop_at_max_x,
:movement_stop_at_max_y,
:movement_stop_at_max_z,
:pin_guard_1_pin_nr,
:pin_guard_1_time_out,
:pin_guard_2_active_state,
:pin_guard_1_active_state,
:pin_guard_2_pin_nr,
:pin_guard_2_time_out,
:pin_guard_3_active_state,
:pin_guard_2_active_state,
:pin_guard_3_pin_nr,
:pin_guard_3_time_out,
:pin_guard_4_active_state,
:pin_guard_3_active_state,
:pin_guard_4_pin_nr,
:pin_guard_4_time_out,
:pin_guard_5_active_state,
:pin_guard_4_active_state,
:pin_guard_5_pin_nr,
:pin_guard_5_time_out,
:pin_guard_5_active_state,
:monitor,
:created_at,
:updated_at

View File

@ -1,5 +1,6 @@
defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
alias FarmbotCore.{Asset, Asset.Device}
alias FarmbotCeleryScript.AST
use GenServer
require FarmbotCore.Logger
@ -12,6 +13,7 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
end
def init(%Device{} = device) do
send(self(), :check_factory_reset)
{:ok, %Device{} = device, 0}
end
@ -19,8 +21,28 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
{:noreply, device}
end
def handle_info(:check_factory_reset, %Device{needs_reset: true} = state) do
ast =
AST.Factory.new()
|> AST.Factory.rpc_request("RESET_DEVICE_NOW")
|> AST.Factory.factory_reset("farmbot_os")
:ok = FarmbotCeleryScript.execute(ast, make_ref())
{:noreply, state}
end
def handle_info(:check_factory_reset, state) do
{:noreply, state}
end
def handle_info({:step_complete, _ref, _}, state) do
{:noreply, state}
end
def handle_cast({:new_data, new_device}, old_device) do
_ = log_changes(new_device, old_device)
send(self(), :check_factory_reset)
{:noreply, new_device}
end
@ -29,22 +51,24 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
:ota_hour,
:mounted_tool_id
]
new_interesting_device = Map.take(new_device, interesting_params) |> MapSet.new()
old_interesting_device = Map.take(old_device, interesting_params) |> MapSet.new()
difference = MapSet.difference(new_interesting_device, old_interesting_device)
Enum.each(difference, fn
{:ota_hour, nil} ->
FarmbotCore.Logger.success 1, "Farmbot will apply updates as soon as possible"
FarmbotCore.Logger.success(1, "Farmbot will apply updates as soon as possible")
{:ota_hour, hour} ->
FarmbotCore.Logger.success 1, "Farmbot will apply updates during the hour of #{hour}:00"
FarmbotCore.Logger.success(1, "Farmbot will apply updates during the hour of #{hour}:00")
{:mounted_tool_id, nil} ->
if old_device.mounted_tool_id do
if tool = Asset.get_tool(id: old_device.mounted_tool_id) do
FarmbotCore.Logger.info 2, "Farmbot dismounted #{tool.name}"
FarmbotCore.Logger.info(2, "Farmbot dismounted #{tool.name}")
else
FarmbotCore.Logger.info 2, "Farmbot dismounted unknown tool"
FarmbotCore.Logger.info(2, "Farmbot dismounted unknown tool")
end
else
# no previously mounted tool
@ -53,9 +77,9 @@ defimpl FarmbotCore.AssetWorker, for: FarmbotCore.Asset.Device do
{:mounted_tool_id, id} ->
if tool = Asset.get_tool(id: id) do
FarmbotCore.Logger.info 2, "Farmbot mounted #{tool.name}"
FarmbotCore.Logger.info(2, "Farmbot mounted #{tool.name}")
else
FarmbotCore.Logger.info 2, "Farmbot mounted unknown tool"
FarmbotCore.Logger.info(2, "Farmbot mounted unknown tool")
end
{_key, _value} ->

View File

@ -28,6 +28,11 @@ defmodule FarmbotCore.BotState do
def set_position(bot_state_server \\ __MODULE__, x, y, z) do
GenServer.call(bot_state_server, {:set_position, x, y, z})
end
@doc "Sets the location_data.load"
def set_load(bot_state_server \\ __MODULE__, x, y, z) do
GenServer.call(bot_state_server, {:set_load, x, y, z})
end
@doc "Sets the location_data.encoders_scaled"
def set_encoders_scaled(bot_state_server \\ __MODULE__, x, y, z) do
@ -217,6 +222,16 @@ defmodule FarmbotCore.BotState do
{:reply, reply, state}
end
def handle_call({:set_load, x, y, z}, _from, state) do
change = %{location_data: %{load: %{x: x, y: y, z: z}}}
{reply, state} =
BotStateNG.changeset(state.tree, change)
|> dispatch_and_apply(state)
{:reply, reply, state}
end
def handle_call({:set_encoders_scaled, x, y, z}, _from, state) do
change = %{location_data: %{scaled_encoders: %{x: x, y: y, z: z}}}

View File

@ -11,6 +11,7 @@ defmodule FarmbotCore.BotStateNG.LocationData do
embeds_one(:scaled_encoders, Vec3, on_replace: :update)
embeds_one(:raw_encoders, Vec3, on_replace: :update)
embeds_one(:position, Vec3, on_replace: :update)
embeds_one(:load, Vec3, on_replace: :update)
embeds_one(:axis_states, Vec3String, on_replace: :update)
end
@ -20,6 +21,7 @@ defmodule FarmbotCore.BotStateNG.LocationData do
|> put_embed(:scaled_encoders, Vec3.new(), [])
|> put_embed(:raw_encoders, Vec3.new(), [])
|> put_embed(:position, Vec3.new(), [])
|> put_embed(:load, Vec3.new(), [])
|> put_embed(:axis_states, Vec3String.new(), [])
|> apply_changes()
end
@ -29,6 +31,7 @@ defmodule FarmbotCore.BotStateNG.LocationData do
scaled_encoders: Vec3.view(location_data.scaled_encoders),
raw_encoders: Vec3.view(location_data.raw_encoders),
position: Vec3.view(location_data.position),
load: Vec3.view(location_data.load),
axis_states: Vec3String.view(location_data.axis_states)
}
end
@ -39,6 +42,7 @@ defmodule FarmbotCore.BotStateNG.LocationData do
|> cast_embed(:scaled_encoders)
|> cast_embed(:raw_encoders)
|> cast_embed(:position)
|> cast_embed(:load)
|> cast_embed(:axis_states)
end
end

View File

@ -7,100 +7,103 @@ defmodule FarmbotCore.BotStateNG.McuParams do
@primary_key false
embedded_schema do
field(:pin_guard_4_time_out, :float)
field(:pin_guard_1_active_state, :float)
field(:encoder_scaling_y, :float)
field(:movement_invert_2_endpoints_x, :float)
field(:movement_min_spd_y, :float)
field(:pin_guard_2_time_out, :float)
field(:param_e_stop_on_mov_err, :float)
field(:param_mov_nr_retry, :float)
field(:movement_timeout_x, :float)
field(:movement_timeout_y, :float)
field(:movement_timeout_z, :float)
field(:movement_keep_active_x, :float)
field(:movement_keep_active_y, :float)
field(:movement_keep_active_z, :float)
field(:movement_home_at_boot_x, :float)
field(:movement_home_at_boot_y, :float)
field(:movement_home_spd_z, :float)
field(:movement_invert_endpoints_z, :float)
field(:pin_guard_1_pin_nr, :float)
field(:movement_invert_endpoints_y, :float)
field(:movement_max_spd_y, :float)
field(:movement_home_up_y, :float)
field(:encoder_missed_steps_decay_z, :float)
field(:movement_home_spd_y, :float)
field(:encoder_use_for_pos_x, :float)
field(:movement_step_per_mm_x, :float)
field(:movement_home_at_boot_z, :float)
field(:movement_steps_acc_dec_z, :float)
field(:pin_guard_5_pin_nr, :float)
field(:movement_invert_motor_z, :float)
field(:movement_max_spd_x, :float)
field(:movement_invert_endpoints_x, :float)
field(:movement_invert_endpoints_y, :float)
field(:movement_invert_endpoints_z, :float)
field(:movement_enable_endpoints_x, :float)
field(:movement_enable_endpoints_y, :float)
field(:movement_enable_endpoints_z, :float)
field(:movement_stop_at_home_x, :float)
field(:movement_axis_nr_steps_y, :float)
field(:pin_guard_1_time_out, :float)
field(:movement_home_at_boot_x, :float)
field(:pin_guard_2_pin_nr, :float)
field(:encoder_scaling_z, :float)
field(:param_e_stop_on_mov_err, :float)
field(:encoder_enabled_x, :float)
field(:pin_guard_2_active_state, :float)
field(:encoder_missed_steps_decay_y, :float)
field(:movement_home_up_z, :float)
field(:movement_enable_endpoints_x, :float)
field(:movement_step_per_mm_y, :float)
field(:pin_guard_3_pin_nr, :float)
field(:param_mov_nr_retry, :float)
field(:movement_stop_at_home_z, :float)
field(:pin_guard_4_active_state, :float)
field(:movement_steps_acc_dec_y, :float)
field(:movement_home_spd_x, :float)
field(:movement_keep_active_x, :float)
field(:pin_guard_3_time_out, :float)
field(:movement_keep_active_y, :float)
field(:encoder_scaling_x, :float)
field(:movement_invert_2_endpoints_z, :float)
field(:encoder_missed_steps_decay_x, :float)
field(:movement_timeout_z, :float)
field(:encoder_missed_steps_max_z, :float)
field(:movement_min_spd_z, :float)
field(:encoder_enabled_y, :float)
field(:encoder_type_y, :float)
field(:movement_home_up_x, :float)
field(:pin_guard_3_active_state, :float)
field(:movement_invert_motor_x, :float)
field(:movement_keep_active_z, :float)
field(:movement_max_spd_z, :float)
field(:movement_secondary_motor_invert_x, :float)
field(:movement_stop_at_max_x, :float)
field(:movement_steps_acc_dec_x, :float)
field(:pin_guard_4_pin_nr, :float)
field(:encoder_type_x, :float)
field(:movement_invert_2_endpoints_y, :float)
field(:encoder_invert_y, :float)
field(:movement_axis_nr_steps_x, :float)
field(:movement_stop_at_max_z, :float)
field(:movement_invert_endpoints_x, :float)
field(:encoder_invert_z, :float)
field(:encoder_use_for_pos_z, :float)
field(:pin_guard_5_active_state, :float)
field(:movement_step_per_mm_z, :float)
field(:encoder_enabled_z, :float)
field(:movement_secondary_motor_x, :float)
field(:pin_guard_5_time_out, :float)
field(:movement_min_spd_x, :float)
field(:encoder_type_z, :float)
field(:movement_stop_at_max_y, :float)
field(:encoder_use_for_pos_y, :float)
field(:encoder_missed_steps_max_y, :float)
field(:movement_timeout_x, :float)
field(:movement_stop_at_home_y, :float)
field(:movement_axis_nr_steps_z, :float)
field(:encoder_invert_x, :float)
field(:encoder_missed_steps_max_x, :float)
field(:movement_invert_motor_y, :float)
field(:movement_invert_motor_z, :float)
field(:movement_secondary_motor_x, :float)
field(:movement_secondary_motor_invert_x, :float)
field(:movement_steps_acc_dec_x, :float)
field(:movement_steps_acc_dec_y, :float)
field(:movement_steps_acc_dec_z, :float)
field(:movement_stop_at_home_x, :float)
field(:movement_stop_at_home_y, :float)
field(:movement_stop_at_home_z, :float)
field(:movement_home_up_x, :float)
field(:movement_home_up_y, :float)
field(:movement_home_up_z, :float)
field(:movement_step_per_mm_x, :float)
field(:movement_step_per_mm_y, :float)
field(:movement_step_per_mm_z, :float)
field(:movement_min_spd_x, :float)
field(:movement_min_spd_y, :float)
field(:movement_min_spd_z, :float)
field(:movement_home_spd_x, :float)
field(:movement_home_spd_y, :float)
field(:movement_home_spd_z, :float)
field(:movement_max_spd_x, :float)
field(:movement_max_spd_y, :float)
field(:movement_max_spd_z, :float)
field(:movement_invert_2_endpoints_x, :float)
field(:movement_invert_2_endpoints_y, :float)
field(:movement_invert_2_endpoints_z, :float)
field(:movement_motor_current_x, :float)
field(:movement_motor_current_y, :float)
field(:movement_motor_current_z, :float)
field(:movement_stall_sensitivity_x, :float)
field(:movement_stall_sensitivity_y, :float)
field(:movement_stall_sensitivity_z, :float)
field(:movement_microsteps_x, :float)
field(:movement_microsteps_y, :float)
field(:movement_microsteps_z, :float)
field(:encoder_enabled_x, :float)
field(:encoder_enabled_y, :float)
field(:encoder_enabled_z, :float)
field(:encoder_type_x, :float)
field(:encoder_type_y, :float)
field(:encoder_type_z, :float)
field(:encoder_missed_steps_max_x, :float)
field(:encoder_missed_steps_max_y, :float)
field(:encoder_missed_steps_max_z, :float)
field(:encoder_scaling_x, :float)
field(:encoder_scaling_y, :float)
field(:encoder_scaling_z, :float)
field(:encoder_missed_steps_decay_x, :float)
field(:encoder_missed_steps_decay_y, :float)
field(:encoder_missed_steps_decay_z, :float)
field(:encoder_use_for_pos_x, :float)
field(:encoder_use_for_pos_y, :float)
field(:encoder_use_for_pos_z, :float)
field(:encoder_invert_x, :float)
field(:encoder_invert_y, :float)
field(:encoder_invert_z, :float)
field(:movement_axis_nr_steps_x, :float)
field(:movement_axis_nr_steps_y, :float)
field(:movement_axis_nr_steps_z, :float)
field(:movement_stop_at_max_x, :float)
field(:movement_stop_at_max_y, :float)
field(:movement_stop_at_max_z, :float)
field(:pin_guard_1_pin_nr, :float)
field(:pin_guard_1_time_out, :float)
field(:pin_guard_1_active_state, :float)
field(:pin_guard_2_pin_nr, :float)
field(:pin_guard_2_time_out, :float)
field(:pin_guard_2_active_state, :float)
field(:pin_guard_3_pin_nr, :float)
field(:pin_guard_3_time_out, :float)
field(:pin_guard_3_active_state, :float)
field(:pin_guard_4_pin_nr, :float)
field(:pin_guard_4_time_out, :float)
field(:pin_guard_4_active_state, :float)
field(:pin_guard_5_pin_nr, :float)
field(:pin_guard_5_time_out, :float)
field(:pin_guard_5_active_state, :float)
end
def new() do
@ -111,200 +114,206 @@ defmodule FarmbotCore.BotStateNG.McuParams do
def view(mcu_params) do
%{
pin_guard_4_time_out: mcu_params.pin_guard_4_time_out,
pin_guard_1_active_state: mcu_params.pin_guard_1_active_state,
encoder_scaling_y: mcu_params.encoder_scaling_y,
movement_invert_2_endpoints_x: mcu_params.movement_invert_2_endpoints_x,
movement_min_spd_y: mcu_params.movement_min_spd_y,
pin_guard_2_time_out: mcu_params.pin_guard_2_time_out,
param_e_stop_on_mov_err: mcu_params.param_e_stop_on_mov_err,
param_mov_nr_retry: mcu_params.param_mov_nr_retry,
movement_timeout_x: mcu_params.movement_timeout_x,
movement_timeout_y: mcu_params.movement_timeout_y,
movement_timeout_z: mcu_params.movement_timeout_z,
movement_keep_active_x: mcu_params.movement_keep_active_x,
movement_keep_active_y: mcu_params.movement_keep_active_y,
movement_keep_active_z: mcu_params.movement_keep_active_z,
movement_home_at_boot_x: mcu_params.movement_home_at_boot_x,
movement_home_at_boot_y: mcu_params.movement_home_at_boot_y,
movement_home_spd_z: mcu_params.movement_home_spd_z,
movement_invert_endpoints_z: mcu_params.movement_invert_endpoints_z,
pin_guard_1_pin_nr: mcu_params.pin_guard_1_pin_nr,
movement_invert_endpoints_y: mcu_params.movement_invert_endpoints_y,
movement_max_spd_y: mcu_params.movement_max_spd_y,
movement_home_up_y: mcu_params.movement_home_up_y,
encoder_missed_steps_decay_z: mcu_params.encoder_missed_steps_decay_z,
movement_home_spd_y: mcu_params.movement_home_spd_y,
encoder_use_for_pos_x: mcu_params.encoder_use_for_pos_x,
movement_step_per_mm_x: mcu_params.movement_step_per_mm_x,
movement_home_at_boot_z: mcu_params.movement_home_at_boot_z,
movement_steps_acc_dec_z: mcu_params.movement_steps_acc_dec_z,
pin_guard_5_pin_nr: mcu_params.pin_guard_5_pin_nr,
movement_invert_motor_z: mcu_params.movement_invert_motor_z,
movement_max_spd_x: mcu_params.movement_max_spd_x,
movement_invert_endpoints_x: mcu_params.movement_invert_endpoints_x,
movement_invert_endpoints_y: mcu_params.movement_invert_endpoints_y,
movement_invert_endpoints_z: mcu_params.movement_invert_endpoints_z,
movement_enable_endpoints_x: mcu_params.movement_enable_endpoints_x,
movement_enable_endpoints_y: mcu_params.movement_enable_endpoints_y,
movement_enable_endpoints_z: mcu_params.movement_enable_endpoints_z,
movement_stop_at_home_x: mcu_params.movement_stop_at_home_x,
movement_axis_nr_steps_y: mcu_params.movement_axis_nr_steps_y,
pin_guard_1_time_out: mcu_params.pin_guard_1_time_out,
movement_home_at_boot_x: mcu_params.movement_home_at_boot_x,
pin_guard_2_pin_nr: mcu_params.pin_guard_2_pin_nr,
encoder_scaling_z: mcu_params.encoder_scaling_z,
param_e_stop_on_mov_err: mcu_params.param_e_stop_on_mov_err,
encoder_enabled_x: mcu_params.encoder_enabled_x,
pin_guard_2_active_state: mcu_params.pin_guard_2_active_state,
encoder_missed_steps_decay_y: mcu_params.encoder_missed_steps_decay_y,
movement_home_up_z: mcu_params.movement_home_up_z,
movement_enable_endpoints_x: mcu_params.movement_enable_endpoints_x,
movement_step_per_mm_y: mcu_params.movement_step_per_mm_y,
pin_guard_3_pin_nr: mcu_params.pin_guard_3_pin_nr,
param_mov_nr_retry: mcu_params.param_mov_nr_retry,
movement_stop_at_home_z: mcu_params.movement_stop_at_home_z,
pin_guard_4_active_state: mcu_params.pin_guard_4_active_state,
movement_steps_acc_dec_y: mcu_params.movement_steps_acc_dec_y,
movement_home_spd_x: mcu_params.movement_home_spd_x,
movement_keep_active_x: mcu_params.movement_keep_active_x,
pin_guard_3_time_out: mcu_params.pin_guard_3_time_out,
movement_keep_active_y: mcu_params.movement_keep_active_y,
encoder_scaling_x: mcu_params.encoder_scaling_x,
movement_invert_2_endpoints_z: mcu_params.movement_invert_2_endpoints_z,
encoder_missed_steps_decay_x: mcu_params.encoder_missed_steps_decay_x,
movement_timeout_z: mcu_params.movement_timeout_z,
encoder_missed_steps_max_z: mcu_params.encoder_missed_steps_max_z,
movement_min_spd_z: mcu_params.movement_min_spd_z,
encoder_enabled_y: mcu_params.encoder_enabled_y,
encoder_type_y: mcu_params.encoder_type_y,
movement_home_up_x: mcu_params.movement_home_up_x,
pin_guard_3_active_state: mcu_params.pin_guard_3_active_state,
movement_invert_motor_x: mcu_params.movement_invert_motor_x,
movement_keep_active_z: mcu_params.movement_keep_active_z,
movement_max_spd_z: mcu_params.movement_max_spd_z,
movement_secondary_motor_invert_x: mcu_params.movement_secondary_motor_invert_x,
movement_stop_at_max_x: mcu_params.movement_stop_at_max_x,
movement_steps_acc_dec_x: mcu_params.movement_steps_acc_dec_x,
pin_guard_4_pin_nr: mcu_params.pin_guard_4_pin_nr,
encoder_type_x: mcu_params.encoder_type_x,
movement_invert_2_endpoints_y: mcu_params.movement_invert_2_endpoints_y,
encoder_invert_y: mcu_params.encoder_invert_y,
movement_axis_nr_steps_x: mcu_params.movement_axis_nr_steps_x,
movement_stop_at_max_z: mcu_params.movement_stop_at_max_z,
movement_invert_endpoints_x: mcu_params.movement_invert_endpoints_x,
encoder_invert_z: mcu_params.encoder_invert_z,
encoder_use_for_pos_z: mcu_params.encoder_use_for_pos_z,
pin_guard_5_active_state: mcu_params.pin_guard_5_active_state,
movement_step_per_mm_z: mcu_params.movement_step_per_mm_z,
encoder_enabled_z: mcu_params.encoder_enabled_z,
movement_secondary_motor_x: mcu_params.movement_secondary_motor_x,
pin_guard_5_time_out: mcu_params.pin_guard_5_time_out,
movement_min_spd_x: mcu_params.movement_min_spd_x,
encoder_type_z: mcu_params.encoder_type_z,
movement_stop_at_max_y: mcu_params.movement_stop_at_max_y,
encoder_use_for_pos_y: mcu_params.encoder_use_for_pos_y,
encoder_missed_steps_max_y: mcu_params.encoder_missed_steps_max_y,
movement_timeout_x: mcu_params.movement_timeout_x,
movement_stop_at_home_y: mcu_params.movement_stop_at_home_y,
movement_axis_nr_steps_z: mcu_params.movement_axis_nr_steps_z,
encoder_invert_x: mcu_params.encoder_invert_x,
encoder_missed_steps_max_x: mcu_params.encoder_missed_steps_max_x,
movement_invert_motor_y: mcu_params.movement_invert_motor_y,
movement_invert_motor_z: mcu_params.movement_invert_motor_z,
movement_secondary_motor_x: mcu_params.movement_secondary_motor_x,
movement_secondary_motor_invert_x: mcu_params.movement_secondary_motor_invert_x,
movement_steps_acc_dec_x: mcu_params.movement_steps_acc_dec_x,
movement_steps_acc_dec_y: mcu_params.movement_steps_acc_dec_y,
movement_steps_acc_dec_z: mcu_params.movement_steps_acc_dec_z,
movement_stop_at_home_x: mcu_params.movement_stop_at_home_x,
movement_stop_at_home_y: mcu_params.movement_stop_at_home_y,
movement_stop_at_home_z: mcu_params.movement_stop_at_home_z,
movement_home_up_x: mcu_params.movement_home_up_x,
movement_home_up_y: mcu_params.movement_home_up_y,
movement_home_up_z: mcu_params.movement_home_up_z,
movement_step_per_mm_x: mcu_params.movement_step_per_mm_x,
movement_step_per_mm_y: mcu_params.movement_step_per_mm_y,
movement_step_per_mm_z: mcu_params.movement_step_per_mm_z,
movement_min_spd_x: mcu_params.movement_min_spd_x,
movement_min_spd_y: mcu_params.movement_min_spd_y,
movement_min_spd_z: mcu_params.movement_min_spd_z,
movement_home_spd_x: mcu_params.movement_home_spd_x,
movement_home_spd_y: mcu_params.movement_home_spd_y,
movement_home_spd_z: mcu_params.movement_home_spd_z,
movement_max_spd_x: mcu_params.movement_max_spd_x,
movement_max_spd_y: mcu_params.movement_max_spd_y,
movement_max_spd_z: mcu_params.movement_max_spd_z,
movement_invert_2_endpoints_x: mcu_params.movement_invert_2_endpoints_x,
movement_invert_2_endpoints_y: mcu_params.movement_invert_2_endpoints_y,
movement_invert_2_endpoints_z: mcu_params.movement_invert_2_endpoints_z,
movement_motor_current_x: mcu_params.movement_motor_current_x,
movement_motor_current_y: mcu_params.movement_motor_current_y,
movement_motor_current_z: mcu_params.movement_motor_current_z,
movement_stall_sensitivity_x: mcu_params.movement_stall_sensitivity_x,
movement_stall_sensitivity_y: mcu_params.movement_stall_sensitivity_y,
movement_stall_sensitivity_z: mcu_params.movement_stall_sensitivity_z
movement_stall_sensitivity_z: mcu_params.movement_stall_sensitivity_z,
movement_microsteps_x: mcu_params.movement_microsteps_x,
movement_microsteps_y: mcu_params.movement_microsteps_y,
movement_microsteps_z: mcu_params.movement_microsteps_z,
encoder_enabled_x: mcu_params.encoder_enabled_x,
encoder_enabled_y: mcu_params.encoder_enabled_y,
encoder_enabled_z: mcu_params.encoder_enabled_z,
encoder_type_x: mcu_params.encoder_type_x,
encoder_type_y: mcu_params.encoder_type_y,
encoder_type_z: mcu_params.encoder_type_z,
encoder_missed_steps_max_x: mcu_params.encoder_missed_steps_max_x,
encoder_missed_steps_max_y: mcu_params.encoder_missed_steps_max_y,
encoder_missed_steps_max_z: mcu_params.encoder_missed_steps_max_z,
encoder_scaling_x: mcu_params.encoder_scaling_x,
encoder_scaling_y: mcu_params.encoder_scaling_y,
encoder_scaling_z: mcu_params.encoder_scaling_z,
encoder_missed_steps_decay_x: mcu_params.encoder_missed_steps_decay_x,
encoder_missed_steps_decay_y: mcu_params.encoder_missed_steps_decay_y,
encoder_missed_steps_decay_z: mcu_params.encoder_missed_steps_decay_z,
encoder_use_for_pos_x: mcu_params.encoder_use_for_pos_x,
encoder_use_for_pos_y: mcu_params.encoder_use_for_pos_y,
encoder_use_for_pos_z: mcu_params.encoder_use_for_pos_z,
encoder_invert_x: mcu_params.encoder_invert_x,
encoder_invert_y: mcu_params.encoder_invert_y,
encoder_invert_z: mcu_params.encoder_invert_z,
movement_axis_nr_steps_x: mcu_params.movement_axis_nr_steps_x,
movement_axis_nr_steps_y: mcu_params.movement_axis_nr_steps_y,
movement_axis_nr_steps_z: mcu_params.movement_axis_nr_steps_z,
movement_stop_at_max_x: mcu_params.movement_stop_at_max_x,
movement_stop_at_max_y: mcu_params.movement_stop_at_max_y,
movement_stop_at_max_z: mcu_params.movement_stop_at_max_z,
pin_guard_1_pin_nr: mcu_params.pin_guard_1_pin_nr,
pin_guard_1_time_out: mcu_params.pin_guard_1_time_out,
pin_guard_1_active_state: mcu_params.pin_guard_1_active_state,
pin_guard_2_pin_nr: mcu_params.pin_guard_2_pin_nr,
pin_guard_2_time_out: mcu_params.pin_guard_2_time_out,
pin_guard_2_active_state: mcu_params.pin_guard_2_active_state,
pin_guard_3_pin_nr: mcu_params.pin_guard_3_pin_nr,
pin_guard_3_time_out: mcu_params.pin_guard_3_time_out,
pin_guard_3_active_state: mcu_params.pin_guard_3_active_state,
pin_guard_4_pin_nr: mcu_params.pin_guard_4_pin_nr,
pin_guard_4_time_out: mcu_params.pin_guard_4_time_out,
pin_guard_4_active_state: mcu_params.pin_guard_4_active_state,
pin_guard_5_pin_nr: mcu_params.pin_guard_5_pin_nr,
pin_guard_5_time_out: mcu_params.pin_guard_5_time_out,
pin_guard_5_active_state: :pin_guard_5_active_stat
}
end
def changeset(mcu_params, params \\ %{}) do
mcu_params
|> cast(params, [
:pin_guard_4_time_out,
:pin_guard_1_active_state,
:encoder_scaling_y,
:movement_invert_2_endpoints_x,
:movement_min_spd_y,
:pin_guard_2_time_out,
:param_e_stop_on_mov_err,
:param_mov_nr_retry,
:movement_timeout_x,
:movement_timeout_y,
:movement_timeout_z,
:movement_keep_active_x,
:movement_keep_active_y,
:movement_keep_active_z,
:movement_home_at_boot_x,
:movement_home_at_boot_y,
:movement_home_spd_z,
:movement_invert_endpoints_z,
:pin_guard_1_pin_nr,
:movement_invert_endpoints_y,
:movement_max_spd_y,
:movement_home_up_y,
:encoder_missed_steps_decay_z,
:movement_home_spd_y,
:encoder_use_for_pos_x,
:movement_step_per_mm_x,
:movement_home_at_boot_z,
:movement_steps_acc_dec_z,
:pin_guard_5_pin_nr,
:movement_invert_motor_z,
:movement_max_spd_x,
:movement_invert_endpoints_x,
:movement_invert_endpoints_y,
:movement_invert_endpoints_z,
:movement_enable_endpoints_x,
:movement_enable_endpoints_y,
:movement_enable_endpoints_z,
:movement_stop_at_home_x,
:movement_axis_nr_steps_y,
:pin_guard_1_time_out,
:movement_home_at_boot_x,
:pin_guard_2_pin_nr,
:encoder_scaling_z,
:param_e_stop_on_mov_err,
:encoder_enabled_x,
:pin_guard_2_active_state,
:encoder_missed_steps_decay_y,
:movement_home_up_z,
:movement_enable_endpoints_x,
:movement_step_per_mm_y,
:pin_guard_3_pin_nr,
:param_mov_nr_retry,
:movement_stop_at_home_z,
:pin_guard_4_active_state,
:movement_steps_acc_dec_y,
:movement_home_spd_x,
:movement_keep_active_x,
:pin_guard_3_time_out,
:movement_keep_active_y,
:encoder_scaling_x,
:movement_invert_2_endpoints_z,
:encoder_missed_steps_decay_x,
:movement_timeout_z,
:encoder_missed_steps_max_z,
:movement_min_spd_z,
:encoder_enabled_y,
:encoder_type_y,
:movement_home_up_x,
:pin_guard_3_active_state,
:movement_invert_motor_x,
:movement_keep_active_z,
:movement_max_spd_z,
:movement_secondary_motor_invert_x,
:movement_stop_at_max_x,
:movement_steps_acc_dec_x,
:pin_guard_4_pin_nr,
:encoder_type_x,
:movement_invert_2_endpoints_y,
:encoder_invert_y,
:movement_axis_nr_steps_x,
:movement_stop_at_max_z,
:movement_invert_endpoints_x,
:encoder_invert_z,
:encoder_use_for_pos_z,
:pin_guard_5_active_state,
:movement_step_per_mm_z,
:encoder_enabled_z,
:movement_secondary_motor_x,
:pin_guard_5_time_out,
:movement_min_spd_x,
:encoder_type_z,
:movement_stop_at_max_y,
:encoder_use_for_pos_y,
:encoder_missed_steps_max_y,
:movement_timeout_x,
:movement_stop_at_home_y,
:movement_axis_nr_steps_z,
:encoder_invert_x,
:encoder_missed_steps_max_x,
:movement_invert_motor_y,
:movement_invert_motor_z,
:movement_secondary_motor_x,
:movement_secondary_motor_invert_x,
:movement_steps_acc_dec_x,
:movement_steps_acc_dec_y,
:movement_steps_acc_dec_z,
:movement_stop_at_home_x,
:movement_stop_at_home_y,
:movement_stop_at_home_z,
:movement_home_up_x,
:movement_home_up_y,
:movement_home_up_z,
:movement_step_per_mm_x,
:movement_step_per_mm_y,
:movement_step_per_mm_z,
:movement_min_spd_x,
:movement_min_spd_y,
:movement_min_spd_z,
:movement_home_spd_x,
:movement_home_spd_y,
:movement_home_spd_z,
:movement_max_spd_x,
:movement_max_spd_y,
:movement_max_spd_z,
:movement_invert_2_endpoints_x,
:movement_invert_2_endpoints_y,
:movement_invert_2_endpoints_z,
:movement_motor_current_x,
:movement_motor_current_y,
:movement_motor_current_z,
:movement_stall_sensitivity_x,
:movement_stall_sensitivity_y,
:movement_stall_sensitivity_z
:movement_stall_sensitivity_z,
:movement_microsteps_x,
:movement_microsteps_y,
:movement_microsteps_z,
:encoder_enabled_x,
:encoder_enabled_y,
:encoder_enabled_z,
:encoder_type_x,
:encoder_type_y,
:encoder_type_z,
:encoder_missed_steps_max_x,
:encoder_missed_steps_max_y,
:encoder_missed_steps_max_z,
:encoder_scaling_x,
:encoder_scaling_y,
:encoder_scaling_z,
:encoder_missed_steps_decay_x,
:encoder_missed_steps_decay_y,
:encoder_missed_steps_decay_z,
:encoder_use_for_pos_x,
:encoder_use_for_pos_y,
:encoder_use_for_pos_z,
:encoder_invert_x,
:encoder_invert_y,
:encoder_invert_z,
:movement_axis_nr_steps_x,
:movement_axis_nr_steps_y,
:movement_axis_nr_steps_z,
:movement_stop_at_max_x,
:movement_stop_at_max_y,
:movement_stop_at_max_z,
:pin_guard_1_pin_nr,
:pin_guard_1_time_out,
:pin_guard_1_active_state,
:pin_guard_2_pin_nr,
:pin_guard_2_time_out,
:pin_guard_2_active_state,
:pin_guard_3_pin_nr,
:pin_guard_3_time_out,
:pin_guard_3_active_state,
:pin_guard_4_pin_nr,
:pin_guard_4_time_out,
:pin_guard_4_active_state,
:pin_guard_5_pin_nr,
:pin_guard_5_time_out,
:pin_guard_5_active_state
])
end
end

View File

@ -10,6 +10,11 @@ defmodule FarmbotCore.FirmwareSideEffects do
:ok = BotState.set_position(x, y, z)
end
@impl FarmbotFirmware.SideEffects
def handle_load(x: x, y: y, z: z) do
:ok = BotState.set_load(x, y, z)
end
@impl FarmbotFirmware.SideEffects
def handle_position_change([{_axis, _value}]) do
:noop
@ -83,6 +88,10 @@ defmodule FarmbotCore.FirmwareSideEffects do
[_, _, _, "G"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino_k14")
# Farmduino V15
[_, _, _, "H"] ->
_ = Leds.red(:solid)
:ok = BotState.set_firmware_hardware("farmduino_k15")
# Express V10
[_, _, _, "E"] ->
_ = Leds.red(:solid)
@ -176,15 +185,6 @@ defmodule FarmbotCore.FirmwareSideEffects do
:movement_invert_endpoints_x,
:movement_invert_endpoints_y,
:movement_invert_endpoints_z,
:movement_invert_2_endpoints_x,
:movement_invert_2_endpoints_y,
:movement_invert_2_endpoints_z,
:movement_motor_current_x,
:movement_motor_current_y,
:movement_motor_current_z,
:movement_stall_sensitivity_x,
:movement_stall_sensitivity_y,
:movement_stall_sensitivity_z,
:movement_enable_endpoints_x,
:movement_enable_endpoints_y,
:movement_enable_endpoints_z,
@ -214,6 +214,18 @@ defmodule FarmbotCore.FirmwareSideEffects do
:movement_max_spd_x,
:movement_max_spd_y,
:movement_max_spd_z,
:movement_invert_2_endpoints_x,
:movement_invert_2_endpoints_y,
:movement_invert_2_endpoints_z,
:movement_motor_current_x,
:movement_motor_current_y,
:movement_motor_current_z,
:movement_stall_sensitivity_x,
:movement_stall_sensitivity_y,
:movement_stall_sensitivity_z,
:movement_microsteps_x,
:movement_microsteps_y,
:movement_microsteps_z,
:encoder_enabled_x,
:encoder_enabled_y,
:encoder_enabled_z,

View File

@ -40,7 +40,11 @@ defmodule FarmbotCore.MixProject do
"coveralls.html": :test
],
source_url: "https://github.com/Farmbot/farmbot_os",
homepage_url: "http://farmbot.io"
homepage_url: "http://farmbot.io",
docs: [
logo: "../farmbot_os/priv/static/farmbot_logo.png",
extras: Path.wildcard("../docs/**/*.md")
]
]
end
@ -65,7 +69,7 @@ defmodule FarmbotCore.MixProject do
{:muontrap, "~> 0.5"},
{:excoveralls, "~> 0.10", only: [:test], targets: [:host]},
{:dialyxir, "~> 1.0.0-rc.3", only: [:dev], targets: [:host], runtime: false},
{:ex_doc, "~> 0.19", only: [:dev], targets: [:host], runtime: false}
{:ex_doc, "~> 0.21.2", only: [:dev], targets: [:host], runtime: false}
]
end

View File

@ -1,6 +1,6 @@
%{
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"circuits_uart": {:hex, :circuits_uart, "1.3.0", "a489e648f358fb3c59e8dd146ead4295cec09d8abae3a0024be2fe3a0b6ddf8b", [:mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"circuits_uart": {:hex, :circuits_uart, "1.4.0", "799abad2d5f355bd571c46de089e62c6341e6b08f9fdf51f4d53d50f5d5bbda9", [:mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.5.0", "4ef3ae066ee10fe01ea3272edc8f024347a0d3eb95f6fbb9aed556dacbfc1337", [:rebar3], [{:cowlib, "~> 2.6.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.6.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
@ -8,25 +8,25 @@
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.3", "774306f84973fc3f1e2e8743eeaa5f5d29b117f3916e5de74c075c02f1b8ef55", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.9", "031d55df9bb430cb118e6f3026a87408d9ce9638737bda3871e5d727a3594aae", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
"esqlite": {:hex, :esqlite, "0.2.4", "3a8a352c190afe2d6b828b252a6fbff65b5cc1124647f38b15bdab3bf6fd4b3e", [:rebar3], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.10.1", "407d50ac8fc63dfee9175ccb4548e6c5512b5052afa63eedb9cd452a32a91495", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"gen_stage": {:hex, :gen_stage, "0.14.1", "9d46723fda072d4f4bb31a102560013f7960f5d80ea44dcb96fd6304ed61e7a4", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.17.1", "8baab33482df4907b3eae22f719da492cee3981a26e649b9c2be1c0192616962", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.10.0", "0f09c2ddf352887a956d84f8f7e702111122ca32fbbc84c2f0569b8b65cbf7fa", [:mix], [{:makeup, "~> 0.5.5", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"muontrap": {:hex, :muontrap, "0.5.0", "0b885a4095e990000d519441bccb8f037a9c4c35908720e7814a516a606be278", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_uart": {:hex, :nerves_uart, "1.2.0", "195424116b925cd3bf9d666be036c2a80655e6ca0f8d447e277667a60005c50e", [:mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
@ -39,7 +39,7 @@
"sqlite_ecto2": {:hex, :sqlite_ecto2, "2.3.1", "fe58926854c3962c4c8710bd1070dd4ba3717ba77250387794cb7a65f77006aa", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "2.2.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: false]}, {:sqlitex, "~> 1.4", [hex: :sqlitex, repo: "hexpm", optional: false]}], "hexpm"},
"sqlitex": {:hex, :sqlitex, "1.4.3", "a50f12d6aeb25f4ebb128453386c09bbba8f5abd3c7713dc5eaa92f359926ac5", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.4", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
"timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "1.0.2", "6c4242c93332b8590a7979eaf5e11e77d971e579805c44931207e32aa6ad3db1", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},

View File

@ -0,0 +1,14 @@
defmodule FarmbotCore.Asset.Repo.Migrations.ResyncFirmwareConfig do
use Ecto.Migration
def change do
alter table("firmware_configs") do
add(:movement_microsteps_x, :float)
add(:movement_microsteps_y, :float)
add(:movement_microsteps_z, :float)
end
# will resync the firmware params
execute("UPDATE firmware_configs SET updated_at = \"1970-11-07 16:52:31.618000\"")
end
end

View File

@ -0,0 +1,12 @@
defmodule FarmbotCore.Asset.Repo.Migrations.AddNeedsResetToDevice do
use Ecto.Migration
def change do
alter table("devices") do
add(:needs_reset, :boolean, default: false)
end
# Invalidate cache of local device resource:
execute("UPDATE devices SET updated_at = \"1970-11-07 16:52:31.618000\"")
end
end

View File

@ -0,0 +1,50 @@
defmodule FarmbotCore.DeviceWorkerTest do
use ExUnit.Case, async: false
alias Farmbot.TestSupport.AssetFixtures
alias FarmbotCore.Asset.Device
alias FarmbotCore.AssetWorker
alias Farmbot.TestSupport.CeleryScript.TestSysCalls
def fresh_device(needs_reset \\ true) do
params = %{needs_reset: needs_reset}
assert %Device{} = dev = AssetFixtures.device_init(params)
dev
end
describe "devices" do
test "triggering of factory reset during init" do
{:ok, _} = TestSysCalls.checkout()
test_pid = self()
dev = fresh_device()
:ok =
TestSysCalls.handle(TestSysCalls, fn
kind, args ->
send(test_pid, {kind, args})
:ok
end)
{:ok, _pid} = AssetWorker.start_link(dev, [])
assert_receive {:factory_reset, ["farmbot_os"]}
end
end
test "triggering of factory reset during update" do
{:ok, _} = TestSysCalls.checkout()
test_pid = self()
dev = fresh_device(false)
:ok =
TestSysCalls.handle(TestSysCalls, fn
kind, args ->
send(test_pid, {kind, args})
:ok
end)
{:ok, pid} = AssetWorker.start_link(dev, [])
refute_receive {:factory_reset, ["farmbot_os"]}
GenServer.cast(pid, {:new_data, %{dev | needs_reset: true}})
assert_receive {:factory_reset, ["farmbot_os"]}
end
end

View File

@ -6,6 +6,8 @@ config :logger, handle_otp_reports: true, handle_sasl_reports: true
config :farmbot_celery_script, FarmbotCeleryScript.SysCalls,
sys_calls: FarmbotCeleryScript.SysCalls.Stubs
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotFirmware.NullReset
import_config "ecto.exs"
import_config "farmbot_core.exs"
import_config "lagger.exs"

View File

@ -60,7 +60,6 @@ defmodule FarmbotExt.AMQP.AutoSyncChannel do
end
def init(args) do
Process.flag(:sensitive, true)
jwt = Keyword.fetch!(args, :jwt)
send(self(), :preload)
{:ok, %State{conn: nil, chan: nil, jwt: jwt, preloaded: false}}

View File

@ -32,7 +32,6 @@ defmodule FarmbotExt.AMQP.BotStateChannel do
@impl GenServer
def init(args) do
jwt = Keyword.fetch!(args, :jwt)
Process.flag(:sensitive, true)
cache = BotState.subscribe()
{:ok, %State{conn: nil, chan: nil, jwt: jwt, cache: cache}, 0}
end

View File

@ -26,7 +26,6 @@ defmodule FarmbotExt.AMQP.CeleryScriptChannel do
def init(args) do
jwt = Keyword.fetch!(args, :jwt)
Process.flag(:sensitive, true)
send(self(), :connect_amqp)
{:ok, %State{conn: nil, chan: nil, jwt: jwt, rpc_requests: %{}}}
end

View File

@ -1,5 +1,7 @@
defmodule FarmbotExt.AMQP.ChannelSupervisor do
@moduledoc false
@moduledoc """
Supervises AMQP channels
"""
use Supervisor
alias FarmbotExt.JWT
@ -17,7 +19,6 @@ defmodule FarmbotExt.AMQP.ChannelSupervisor do
end
def init([token]) do
Process.flag(:sensitive, true)
jwt = JWT.decode!(token)
children = [

View File

@ -54,6 +54,9 @@ defmodule FarmbotExt.AMQP.ConnectionWorker do
{:ok, _} <- maybe_purge(chan, chan_name, purge?),
:ok <- Queue.bind(chan, chan_name, @exchange, routing_key: route),
{:ok, _} <- Basic.consume(chan, chan_name, self(), no_ack: true) do
# link to the connection and channel because the
# AMQP lib doesn't handle being disconnected form the
# network very well and these pids will turn into zombies
Process.link(conn.pid)
Process.link(chan.pid)
FarmbotTelemetry.event(:amqp, :channel_open)
@ -92,7 +95,6 @@ defmodule FarmbotExt.AMQP.ConnectionWorker do
@impl GenServer
def init(opts) do
Process.flag(:sensitive, true)
Process.flag(:trap_exit, true)
{:ok, %ConnectionWorker{conn: nil, opts: opts}, 0}
end

View File

@ -27,7 +27,6 @@ defmodule FarmbotExt.AMQP.LogChannel do
def init(args) do
jwt = Keyword.fetch!(args, :jwt)
Process.flag(:sensitive, true)
{:ok, %State{conn: nil, chan: nil, jwt: jwt, state_cache: nil}, 0}
end

View File

@ -1,9 +1,13 @@
defmodule FarmbotExt.AMQP.PingPongChannel do
@moduledoc """
This module provides an AMQP channel for
auto-sync messages from the FarmBot API.
SEE:
https://developer.farm.bot/docs/realtime-updates-auto-sync#section-example-auto-sync-subscriptions
AMQP channel responsible for responding to `ping` messages.
Simply echos the exact data received on the `ping` channel
onto the `pong` channel.
Also has a ~15-20 minute timer that will do an `HTTP` request
to `/api/device`. This refreshed the `last_seen_api` field which
is required for devices that have `auto_sync` enabled as with
that field enabled, the device would never do an HTTP request
"""
use GenServer
use AMQP
@ -29,7 +33,6 @@ defmodule FarmbotExt.AMQP.PingPongChannel do
end
def init(args) do
Process.flag(:sensitive, true)
jwt = Keyword.fetch!(args, :jwt)
http_ping_timer = Process.send_after(self(), :http_ping, 5000)
send(self(), :connect_amqp)

View File

@ -1,5 +1,7 @@
defmodule FarmbotExt.AMQP.Supervisor do
@moduledoc false
@moduledoc """
Supervises AMQP connections
"""
use Supervisor
import FarmbotCore.Config, only: [get_config_value: 3]

View File

@ -1,6 +1,9 @@
defmodule FarmbotExt.AMQP.TelemetryChannel do
@moduledoc """
Channel that dispatches telemetry messgaes out of the
DETS database.
"""
use GenServer
use AMQP
@ -22,7 +25,6 @@ defmodule FarmbotExt.AMQP.TelemetryChannel do
end
def init(args) do
Process.flag(:sensitive, true)
jwt = Keyword.fetch!(args, :jwt)
send(self(), :connect_amqp)
cache = BotState.subscribe()

View File

@ -1,6 +1,9 @@
defmodule FarmbotExt.API do
alias FarmbotExt.{API, JWT}
@moduledoc """
Module where all Farmbot specific HTTP calls are done
"""
alias FarmbotExt.{API, JWT}
alias FarmbotCore.JSON
alias FarmbotCore.Asset.{
@ -10,10 +13,8 @@ defmodule FarmbotExt.API do
}
alias FarmbotCore.{BotState, BotState.JobProgress.Percent, Project}
require FarmbotCore.Logger
import FarmbotCore.Config, only: [get_config_value: 3]
use Tesla
alias Tesla.Multipart

View File

@ -53,22 +53,22 @@ defmodule FarmbotExt.API.DirtyWorker do
end
def handle_continue([dirty | rest], %{module: module} = state) do
Logger.info("[#{module} #{dirty.local_id} #{inspect(self())}] Handling dirty data")
# Logger.info("[#{module} #{dirty.local_id} #{inspect(self())}] Handling dirty data")
case http_request(dirty, state) do
# Valid data
{:ok, %{status: s, body: body}} when s > 199 and s < 300 ->
Logger.debug(
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} ok"
)
# Logger.debug(
# "[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} ok"
# )
dirty |> module.changeset(body) |> handle_changeset(rest, state)
# Invalid data
{:ok, %{status: s, body: %{} = body}} when s > 399 and s < 500 ->
Logger.debug(
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} error+body"
)
# Logger.debug(
# "[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} error+body"
# )
changeset = module.changeset(dirty)
@ -79,9 +79,9 @@ defmodule FarmbotExt.API.DirtyWorker do
# Invalid data, but the API didn't say why
{:ok, %{status: s, body: _body}} when s > 399 and s < 500 ->
Logger.debug(
"[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} error"
)
# Logger.debug(
# "[#{module} #{dirty.local_id} #{inspect(self())}] HTTP request complete: #{s} error"
# )
module.changeset(dirty)
|> Map.put(:valid?, false)
@ -101,7 +101,7 @@ defmodule FarmbotExt.API.DirtyWorker do
# If the changeset was valid, update the record.
def handle_changeset(%{valid?: true} = changeset, rest, state) do
Logger.info("Successfully synced: #{state.module}")
# Logger.info("Successfully synced: #{state.module}")
Repo.update!(changeset)
|> Private.mark_clean!()
@ -125,21 +125,21 @@ defmodule FarmbotExt.API.DirtyWorker do
end
defp http_request(%{id: nil} = dirty, state) do
Logger.debug("#{state.module} clean request (post)")
# Logger.debug("#{state.module} clean request (post)")
path = state.module.path()
data = render(state.module, dirty)
API.post(API.client(), path, data)
end
defp http_request(dirty, %{module: module} = state) when module in @singular do
Logger.debug("#{state.module} dirty request (patch)")
# Logger.debug("#{state.module} dirty request (patch)")
path = path = state.module.path()
data = render(state.module, dirty)
API.patch(API.client(), path, data)
end
defp http_request(dirty, state) do
Logger.debug("#{state.module} dirty request (patch)")
# Logger.debug("#{state.module} dirty request (patch)")
path = Path.join(state.module.path(), to_string(dirty.id))
data = render(state.module, dirty)
API.patch(API.client(), path, data)

View File

@ -1,4 +1,9 @@
defmodule FarmbotExt.API.DirtyWorker.Supervisor do
@moduledoc """
Responsible for supervising assets that will need to be
uploaded to the API via a `POST` or `PUT` request.
"""
use Supervisor
alias FarmbotExt.API.DirtyWorker
@ -22,10 +27,12 @@ defmodule FarmbotExt.API.DirtyWorker.Supervisor do
Tool
}
@doc false
def start_link(args) do
Supervisor.start_link(__MODULE__, args, name: __MODULE__)
end
@impl Supervisor
def init(_args) do
children = [
{DirtyWorker, Device},

View File

@ -1,4 +1,9 @@
defmodule FarmbotExt.API.EagerLoader.Supervisor do
@moduledoc """
Responsible for supervising all assets that need to be
eagerloaded
"""
use Supervisor
alias FarmbotExt.API.EagerLoader
@ -22,15 +27,18 @@ defmodule FarmbotExt.API.EagerLoader.Supervisor do
Tool
}
@doc false
def start_link(args) do
Supervisor.start_link(__MODULE__, args, name: __MODULE__)
end
@doc "Drop all cached assets"
def drop_all_cache() do
for {_, pid, _, _} <- Supervisor.which_children(FarmbotExt.API.EagerLoader.Supervisor),
do: GenServer.cast(pid, :drop)
end
@impl Supervisor
def init(_args) do
children = [
{EagerLoader, Device},

View File

@ -45,7 +45,10 @@ defmodule FarmbotExt.API.ImageUploader do
def handle_continue([], state), do: {:noreply, state, @checkup_time_ms}
# TODO(Connor) the meta here is likely inaccurate.
# the meta here is likely inaccurate here because of
# pulling the location data from the cache instead of from the firmware
# directly. It's close enough and getting data from the firmware directly
# would require more work than it is worth
defp try_upload(image_filename) do
%{x: x, y: y, z: z} = BotState.fetch().location_data.position
meta = %{x: x, y: y, z: z, name: Path.rootname(image_filename)}

View File

@ -1,7 +1,11 @@
defmodule FarmbotExt.API.Reconciler do
@moduledoc """
Handles remote additions and changes.
Handles additions, deletions and changes of remote API resources
Uses the `updated_at` and `created_at` common fields of api resources
to determine if FarmbotOS or the API's resource is more current
"""
require Logger
alias Ecto.Changeset
import Ecto.Query
@ -79,7 +83,7 @@ defmodule FarmbotExt.API.Reconciler do
sync_changeset =
Enum.reduce(ids_that_were_deleted, sync_changeset, fn id, sync_changeset ->
Logger.info("delete: #{module} #{inspect(id)}")
# Logger.info("delete: #{module} #{inspect(id)}")
Command.update(module, id, nil)
sync_changeset
end)
@ -95,19 +99,19 @@ defmodule FarmbotExt.API.Reconciler do
case get_changeset(local_item || module, item, cached_cs) do
{:insert, %Changeset{} = cs} ->
Logger.info("insert: #{inspect(cs)}")
# Logger.info("insert: #{inspect(cs)}")
item = module.render(Changeset.apply_changes(cs))
:ok = Command.update(module, item.id, item)
sync_changeset
{:update, %Changeset{} = cs} ->
Logger.info("update: #{inspect(cs)}")
# Logger.info("update: #{inspect(cs)}")
item = module.render(Changeset.apply_changes(cs))
:ok = Command.update(module, item.id, item)
sync_changeset
nil ->
Logger.info("Local data: #{local_item.__struct__} is current.")
# Logger.info("Local data: #{local_item.__struct__} is current.")
sync_changeset
end
end
@ -116,7 +120,7 @@ defmodule FarmbotExt.API.Reconciler do
# A module is passed in if there is no local copy of the data.
defp get_changeset(module, %Item{} = sync_item, nil) when is_atom(module) do
Logger.info("Local data: #{module} does not exist. Using HTTP to get data.")
# Logger.info("Local data: #{module} does not exist. Using HTTP to get data.")
{:ok, changeset} = API.get_changeset(module, "#{sync_item.id}")
{:insert, changeset}
end
@ -128,7 +132,7 @@ defmodule FarmbotExt.API.Reconciler do
if compare_datetimes(sync_item_updated_at, cached_updated_at) == :eq do
{:insert, cached}
else
Logger.info("Cached item is out of date")
# Logger.info("Cached item is out of date")
get_changeset(module, sync_item, nil)
end
end
@ -142,9 +146,9 @@ defmodule FarmbotExt.API.Reconciler do
# Check if remote data is newer
if compare_datetimes(sync_item_updated_at, local_item.updated_at) == :gt do
Logger.info(
"Local data: #{local_item.__struct__} is out of date. Using HTTP to get newer data."
)
# Logger.info(
# "Local data: #{local_item.__struct__} is out of date. Using HTTP to get newer data."
# )
{:ok, changeset} = API.get_changeset(local_item, "#{sync_item_id}")
{:update, changeset}
@ -162,13 +166,13 @@ defmodule FarmbotExt.API.Reconciler do
cache_compare = compare_datetimes(sync_item_updated_at, cached_updated_at)
if cache_compare == :eq || cache_compare == :gt do
Logger.info(
"Local data: #{local_item.__struct__} is out of date. Using cache do get newer data."
)
# Logger.info(
# "Local data: #{local_item.__struct__} is out of date. Using cache do get newer data."
# )
{:update, cached}
else
Logger.info("Cached item is out of date")
# Logger.info("Cached item is out of date")
get_changeset(local_item, sync_item, nil)
end
end

View File

@ -1,18 +1,25 @@
defmodule FarmbotExt.Bootstrap do
use GenServer
@moduledoc """
Task responsible for using
a token, secret, or password for logging into an account
"""
use GenServer
require Logger
alias FarmbotExt.{Bootstrap, Bootstrap.Authorization}
import FarmbotCore.Config, only: [update_config_value: 4, get_config_value: 3]
@doc false
def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end
@impl GenServer
def init([]) do
{:ok, nil, 0}
end
@impl GenServer
def handle_info(:timeout, nil) do
email = get_config_value(:string, "authorization", "email")
server = get_config_value(:string, "authorization", "server")
@ -21,6 +28,8 @@ defmodule FarmbotExt.Bootstrap do
try_auth(email, server, password, secret)
end
# state machine implementation
@doc false
def try_auth(nil, _server, _password, _secret) do
{:noreply, nil, 5000}
end
@ -41,7 +50,6 @@ defmodule FarmbotExt.Bootstrap do
end
end
# TODO(Connor) - drop password and save secret here somehow.
def try_auth(email, server, password, _secret) do
Logger.debug("using password to auth")

View File

@ -9,15 +9,18 @@ defmodule FarmbotExt.Bootstrap.DropPasswordTask do
use GenServer
@doc false
def start_link(args, opts \\ [name: __MODULE__]) do
GenServer.start_link(__MODULE__, args, opts)
end
@impl GenServer
def init(_args) do
send(self(), :checkup)
{:ok, %{backoff: 5000, timer: nil}}
end
@impl GenServer
def handle_info(:checkup, state) do
email = get_config_value(:string, "authorization", "email")
password = get_config_value(:string, "authorization", "password")

View File

@ -1,11 +1,16 @@
defmodule FarmbotExt.Bootstrap.Supervisor do
@moduledoc """
Supervisor responsible for starting all
the tasks and processes that require authentication.
"""
use Supervisor
@doc "Start Bootstraped services."
@doc false
def start_link(args) do
Supervisor.start_link(__MODULE__, args, name: __MODULE__)
end
@impl Supervisor
def init([]) do
children = [
FarmbotExt.API.EagerLoader.Supervisor,

View File

@ -1,4 +1,6 @@
# DELETEME
# TODO(Connor) delete this one day.
# this will require defining farmbot specific encode/decode
# protocols for both of these structures
require Protocol
Protocol.derive(Jason.Encoder, FarmbotExt.JWT)
Protocol.derive(Jason.Encoder, FarmbotCeleryScript.AST)

View File

@ -11,6 +11,7 @@ defmodule FarmbotExt.MixProject do
elixirc_options: [warnings_as_errors: true, ignore_module_conflict: true],
start_permanent: Mix.env() == :prod,
elixirc_paths: ["lib", "vendor"],
deps: deps(),
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
coveralls: :test,
@ -18,7 +19,12 @@ defmodule FarmbotExt.MixProject do
"coveralls.post": :test,
"coveralls.html": :test
],
deps: deps()
source_url: "https://github.com/Farmbot/farmbot_os",
homepage_url: "http://farmbot.io",
docs: [
logo: "../farmbot_os/priv/static/farmbot_logo.png",
extras: Path.wildcard("../docs/**/*.md")
]
]
end
@ -38,11 +44,11 @@ defmodule FarmbotExt.MixProject do
{:tesla, "~> 1.2"},
{:hackney, "~> 1.15"},
{:uuid, "~> 1.1"},
{:amqp, "~> 1.3"},
{:mox, "~> 0.5", only: :test},
{:amqp, "~> 1.4.0"},
{:mox, "~> 0.5.1", only: :test},
{:excoveralls, "~> 0.10", only: [:test], targets: [:host]},
{:dialyxir, "~> 1.0.0-rc.3", only: [:dev], targets: [:host], runtime: false},
{:ex_doc, "~> 0.19", only: [:dev], targets: [:host], runtime: false}
{:ex_doc, "~> 0.21.2", only: [:dev], targets: [:host], runtime: false}
]
end
end

View File

@ -1,19 +1,20 @@
%{
"amqp": {:hex, :amqp, "1.3.0", "246e84fd6b051c5b7fed0c7871df9bc2338bc029085192f61438a1f69180d621", [:mix], [{:amqp_client, "~> 3.7.11", [hex: :amqp_client, repo: "hexpm", optional: false]}, {:goldrush, "~> 0.1.0", [hex: :goldrush, repo: "hexpm", optional: false]}, {:jsx, "~> 2.9", [hex: :jsx, repo: "hexpm", optional: false]}, {:lager, "~> 3.6.5", [hex: :lager, repo: "hexpm", optional: false]}, {:rabbit_common, "~> 3.7.11", [hex: :rabbit_common, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7", [hex: :ranch, repo: "hexpm", optional: false]}, {:recon, "~> 2.3", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm"},
"amqp_client": {:hex, :amqp_client, "3.7.11", "e692b3ba59e6df93c13cec5feefb62c956fcdbae341565101c7668375cc387fe", [:make, :rebar3], [{:rabbit_common, "3.7.11", [hex: :rabbit_common, repo: "hexpm", optional: false]}], "hexpm"},
"amqp": {:hex, :amqp, "1.4.0", "4172595d467b9360850a8eca254c5946af9970684d335d555a9f3410a0e43995", [:mix], [{:amqp_client, "~> 3.8.0", [hex: :amqp_client, repo: "hexpm", optional: false]}], "hexpm"},
"amqp_client": {:hex, :amqp_client, "3.8.2", "b50ac381c3c016a697d6ab8f08367043a08358cfeb8ee97832ccc7d101e59cef", [:make, :rebar3], [{:rabbit_common, "3.8.2", [hex: :rabbit_common, repo: "hexpm", optional: false]}], "hexpm"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"circuits_uart": {:hex, :circuits_uart, "1.3.1", "8c0a56f06828133a0b08363ecb994350a9529d388a912357d31829ae617cd801", [:mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"circuits_uart": {:hex, :circuits_uart, "1.4.0", "799abad2d5f355bd571c46de089e62c6341e6b08f9fdf51f4d53d50f5d5bbda9", [:mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"credentials_obfuscation": {:hex, :credentials_obfuscation, "1.1.0", "513793cc20c18afc9e03e584b436192a751a8344890e03a8741c65c8d6866fab", [:rebar3], [], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.8.0", "ca462e0d885f09a1c5a342dbd7c1dcf27ea63548c65a65e67334f4b61803822e", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.6", "78e97d9c0ff1b5521dd68041193891aebebce52fc3b93463c0a6806874557d7d", [:mix], [{:erlex, "~> 0.2.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.3.2", "b840562ea3d67795ffbb5bd88940b1bed0ed9fa32834915125ea7d02e35888a5", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.9", "031d55df9bb430cb118e6f3026a87408d9ce9638737bda3871e5d727a3594aae", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
"erlex": {:hex, :erlex, "0.2.1", "cee02918660807cbba9a7229cae9b42d1c6143b768c781fa6cee1eaf03ad860b", [:mix], [], "hexpm"},
"esqlite": {:hex, :esqlite, "0.3.0", "f6c96fae1236fd8da73da904278b820c807aee4f41c7c837c33de1c2edb857fb", [:rebar3], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.20.1", "88eaa16e67c505664fd6a66f42ddb962d424ad68df586b214b71443c69887123", [:mix], [{:earmark, "~> 1.3", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.10.6", "e2b9718c9d8e3ef90bc22278c3f76c850a9f9116faf4ebe9678063310742edc2", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"gettext": {:hex, :gettext, "0.16.1", "e2130b25eebcbe02bb343b119a07ae2c7e28bd4b146c4a154da2ffb2b3507af2", [:mix], [], "hexpm"},
"goldrush": {:hex, :goldrush, "0.1.9", "f06e5d5f1277da5c413e84d5a2924174182fb108dabb39d5ec548b27424cd106", [:rebar3], [], "hexpm"},
@ -21,25 +22,25 @@
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"jsx": {:hex, :jsx, "2.9.0", "d2f6e5f069c00266cad52fb15d87c428579ea4d7d73a33669e12679e203329dd", [:mix, :rebar3], [], "hexpm"},
"lager": {:hex, :lager, "3.6.5", "831910109f3fcb503debf658ca0538836b348c58bfbf349a6d48228096ce9040", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
"makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"lager": {:hex, :lager, "3.8.0", "3402b9a7e473680ca179fc2f1d827cab88dd37dd1e6113090c6f45ef05228a1c", [:rebar3], [{:goldrush, "0.1.9", [hex: :goldrush, repo: "hexpm", optional: false]}], "hexpm"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"mox": {:hex, :mox, "0.5.0", "c519b48407017a85f03407a9a4c4ceb7cc6dec5fe886b2241869fb2f08476f9e", [:mix], [], "hexpm"},
"mox": {:hex, :mox, "0.5.1", "f86bb36026aac1e6f924a4b6d024b05e9adbed5c63e8daa069bd66fb3292165b", [:mix], [], "hexpm"},
"muontrap": {:hex, :muontrap, "0.5.0", "0b885a4095e990000d519441bccb8f037a9c4c35908720e7814a516a606be278", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"},
"rabbit_common": {:hex, :rabbit_common, "3.7.11", "dc107a55f6213875264c5ffe014a8d7b34004893d9bc9eb5e16d6c519fb96cf1", [:make, :rebar3], [{:jsx, "2.9.0", [hex: :jsx, repo: "hexpm", optional: false]}, {:lager, "3.6.5", [hex: :lager, repo: "hexpm", optional: false]}, {:ranch, "1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}, {:recon, "2.3.6", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm"},
"rabbit_common": {:hex, :rabbit_common, "3.8.2", "6f5653e7ba8bbf76447b126d1ac224e1be5ed853808542bd67cbcff87fbd2493", [:make, :rebar3], [{:credentials_obfuscation, "1.1.0", [hex: :credentials_obfuscation, repo: "hexpm", optional: false]}, {:jsx, "2.9.0", [hex: :jsx, repo: "hexpm", optional: false]}, {:lager, "3.8.0", [hex: :lager, repo: "hexpm", optional: false]}, {:ranch, "1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}, {:recon, "2.5.0", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"recon": {:hex, :recon, "2.3.6", "2bcad0cf621fb277cabbb6413159cd3aa30265c2dee42c968697988b30108604", [:rebar3], [], "hexpm"},
"recon": {:hex, :recon, "2.5.0", "2f7fcbec2c35034bade2f9717f77059dc54eb4e929a3049ca7ba6775c0bd66cd", [:mix, :rebar3], [], "hexpm"},
"sbroker": {:hex, :sbroker, "1.0.0", "28ff1b5e58887c5098539f236307b36fe1d3edaa2acff9d6a3d17c2dcafebbd0", [:rebar3], [], "hexpm"},
"sqlite_ecto2": {:hex, :sqlite_ecto2, "2.3.1", "fe58926854c3962c4c8710bd1070dd4ba3717ba77250387794cb7a65f77006aa", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "2.2.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: false]}, {:sqlitex, "~> 1.4", [hex: :sqlitex, repo: "hexpm", optional: false]}], "hexpm"},
"sqlitex": {:hex, :sqlitex, "1.5.1", "0242c9a7602180b4f974315e6776c48d4ba211e9f4c5774dc886f15dc1a2edb3", [:mix], [{:decimal, "~> 1.7", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.3.0", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
"tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
"timex": {:hex, :timex, "3.5.0", "b0a23167da02d0fe4f1a4e104d1f929a00d348502b52432c05de875d0b9cffa5", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "0.5.20", "304b9e98a02840fb32a43ec111ffbe517863c8566eb04a061f1c4dbb90b4d84c", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},

View File

@ -129,7 +129,9 @@ defmodule FarmbotFirmware do
:command_queue,
:caller_pid,
:current,
:vcr_fd
:vcr_fd,
:reset,
:reset_pid
]
@type state :: %State{
@ -144,7 +146,9 @@ defmodule FarmbotFirmware do
command_queue: [{pid(), GCODE.t()}],
caller_pid: nil | pid,
current: nil | GCODE.t(),
vcr_fd: nil | File.io_device()
vcr_fd: nil | File.io_device(),
reset: module(),
reset_pid: nil | pid()
}
@doc """
@ -158,7 +162,7 @@ defmodule FarmbotFirmware do
* `{:report_success, []}` -> `:ok`
* `{:report_invalid, []}` -> `{:error, :invalid_command}`
* `{:report_error, []}` -> `{:error, :firmware_error}`
* `{:report_emergency_lock, []}` -> {:error, :emergency_lock}`
* `{:report_emergency_lock, []}` -> `{:error, :emergency_lock}`
If the firmware is in any of the following states:
* `:boot`
@ -200,6 +204,10 @@ defmodule FarmbotFirmware do
GenServer.call(server, {:open_transport, module, args})
end
def reset(server \\ __MODULE__) do
GenServer.call(server, :reset)
end
@doc """
Sets the Firmware server to record input and output GCODES
to a pair of text files.
@ -233,6 +241,7 @@ defmodule FarmbotFirmware do
args = Keyword.merge(args, global)
transport = Keyword.fetch!(args, :transport)
side_effects = Keyword.get(args, :side_effects)
reset = Keyword.fetch!(args, :reset)
vcr_fd =
case Keyword.get(args, :vcr_path) do
@ -256,6 +265,8 @@ defmodule FarmbotFirmware do
transport_args: transport_args,
side_effects: side_effects,
status: :transport_boot,
reset: reset,
reset_pid: nil,
command_queue: [],
configuration_queue: [],
vcr_fd: vcr_fd
@ -273,6 +284,19 @@ defmodule FarmbotFirmware do
GenServer.stop(state.transport_pid)
end
def handle_info(:timeout, %{status: :transport_boot, reset_pid: nil} = state) do
case GenServer.start_link(state.reset, state.transport_args, name: state.reset) do
{:ok, pid} ->
Logger.debug("Firmware reset #{state.reset} started. #{inspect(state.transport_args)}")
{:noreply, %{state | reset_pid: pid}}
error ->
Logger.error("Error starting Firmware Reset: #{inspect(error)}")
Process.send_after(self(), :timeout, @transport_init_error_retry_ms)
{:noreply, state}
end
end
# This will be the first message received right after `init/1`
# It should try to open a transport every `transport_init_error_retry_ms`
# until success.
@ -315,7 +339,7 @@ defmodule FarmbotFirmware do
end
def handle_info(:timeout, %{configuration_queue: [code | rest]} = state) do
Logger.debug("Starting next configuration code: #{inspect(code)}")
# Logger.debug("Starting next configuration code: #{inspect(code)}")
case GenServer.call(state.transport_pid, {state.tag, code}) do
:ok ->
@ -357,6 +381,11 @@ defmodule FarmbotFirmware do
{:noreply, state}
end
def handle_call(:reset, _from, state) do
r = state.reset.reset()
{:reply, r, state}
end
# Closing the transport will purge the buffer of queued commands in both
# the `configuration_queue` and in the `command_queue`.
def handle_call(:close_transport, _from, %{status: s} = state) when s != :transport_boot do
@ -388,7 +417,12 @@ defmodule FarmbotFirmware do
# Add an anon function that transport implementations should call.
fw = self()
fun = fn {_, _} = code -> GenServer.cast(fw, code) end
transport_args = Keyword.put(args, :handle_gcode, fun)
transport_args =
state.transport_args
|> Keyword.merge(args)
|> Keyword.merge(handle_gcode: fun)
next_state = %{state | transport: module, transport_args: transport_args}
send(self(), :timeout)
@ -675,6 +709,14 @@ defmodule FarmbotFirmware do
{:noreply, state}
end
def handle_report({:report_load, load} = code, state) do
if state.caller_pid, do: send(state.caller_pid, {state.tag, code})
for {pid, _code} <- state.command_queue, do: send(pid, {state.tag, {:report_busy, []}})
side_effects(state, :handle_load, [load])
{:noreply, state}
end
def handle_report({:report_axis_state, axis_state} = code, state) do
if state.caller_pid, do: send(state.caller_pid, {state.tag, code})
for {pid, _code} <- state.command_queue, do: send(pid, {state.tag, {:report_busy, []}})

View File

@ -1,5 +1,8 @@
defmodule FarmbotFirmware.Command do
@moduledoc false
# sister module to FarmbotFirmware.Request
# see docs for FarmbotFirmware.command/1
alias FarmbotFirmware
alias FarmbotFirmware.GCODE
require Logger

View File

@ -23,6 +23,7 @@ defmodule FarmbotFirmware.GCODE do
| :report_invalid
| :report_home_complete
| :report_position
| :report_load
| :report_position_change
| :report_parameters_complete
| :report_parameter_value

View File

@ -8,7 +8,8 @@ defmodule FarmbotFirmware.GCODE.Decoder do
def do_decode("R00", []), do: {:report_idle, []}
def do_decode("R01", []), do: {:report_begin, []}
def do_decode("R02", []), do: {:report_success, []}
def do_decode("R03", []), do: {:report_error, []}
def do_decode("R03", []), do: {:report_error, [:no_error]}
def do_decode("R03", error), do: {:report_error, decode_error(error)}
def do_decode("R04", []), do: {:report_busy, []}
def do_decode("R05", xyz), do: {:report_axis_state, decode_axis_state(xyz)}
@ -46,6 +47,7 @@ defmodule FarmbotFirmware.GCODE.Decoder do
def do_decode("R87", []), do: {:report_emergency_lock, []}
def do_decode("R88", []), do: {:report_no_config, []}
def do_decode("R89", xyz), do: {:report_load, decode_floats(xyz)}
def do_decode("R99", debug), do: {:report_debug_message, [Enum.join(debug, " ")]}
def do_decode("G00", xyzs), do: {:command_movement, decode_floats(xyzs)}
@ -82,6 +84,14 @@ defmodule FarmbotFirmware.GCODE.Decoder do
{:unknown, [kind | args]}
end
def decode_error(["V0"]), do: [:no_error]
def decode_error(["V1"]), do: [:emergency_lock]
def decode_error(["V2"]), do: [:timeout]
def decode_error(["V3"]), do: [:stall_detected]
def decode_error(["V14"]), do: [:invalid_command]
def decode_error(["V15"]), do: [:no_config]
def decode_error([unk]), do: [unknown_error: unk]
defp decode_floats(list, acc \\ [])
defp decode_floats([<<arg::binary-1, val::binary>> | rest], acc) do
@ -155,6 +165,8 @@ defmodule FarmbotFirmware.GCODE.Decoder do
defp decode_end_stops([], acc), do: acc
defp decode_end_stops(error, _acc), do: [parse_error: error]
defp decode_pv(["P" <> param_id, "V" <> value]) do
param = Param.decode(String.to_integer(param_id))
{value, ""} = Float.parse(value)

View File

@ -46,6 +46,7 @@ defmodule FarmbotFirmware.GCODE.Encoder do
def do_encode(:report_emergency_lock, []), do: "R87"
def do_encode(:report_no_config, []), do: "R88"
def do_encode(:report_load, xyz), do: "R89 " <> encode_floats(xyz)
def do_encode(:report_debug_message, [message]), do: "R99 " <> message
def do_encode(:command_movement, xyzs), do: "G00 " <> encode_floats(xyzs)

View File

@ -0,0 +1,15 @@
defmodule FarmbotFirmware.NullReset do
@moduledoc """
Does nothing in reference to resetting the firmware port
"""
@behaviour FarmbotFirmware.Reset
use GenServer
@impl FarmbotFirmware.Reset
def reset(), do: :ok
@impl GenServer
def init(_args) do
{:ok, %{}}
end
end

View File

@ -14,6 +14,10 @@ defmodule FarmbotFirmware.PackageUtils do
Application.app_dir(:farmbot_firmware, ["priv", "farmduino_k14.hex"]) |> assert_exists()
end
def find_hex_file("farmduino_k15") do
Application.app_dir(:farmbot_firmware, ["priv", "farmduino_k15.hex"]) |> assert_exists()
end
def find_hex_file("express_k10") do
Application.app_dir(:farmbot_firmware, ["priv", "express_k10.hex"]) |> assert_exists()
end
@ -35,6 +39,9 @@ defmodule FarmbotFirmware.PackageUtils do
def package_to_string("farmduino_k14"),
do: "Farmduino (Genesis v1.4)"
def package_to_string("farmduino_k15"),
do: "Farmduino (Genesis v1.5)"
def package_to_string("express_k10"),
do: "Farmduino (Express v1.0)"

View File

@ -62,6 +62,9 @@ defmodule FarmbotFirmware.Param do
def decode(85), do: :movement_stall_sensitivity_x
def decode(86), do: :movement_stall_sensitivity_y
def decode(87), do: :movement_stall_sensitivity_z
def decode(91), do: :movement_microsteps_x
def decode(92), do: :movement_microsteps_y
def decode(93), do: :movement_microsteps_z
def decode(101), do: :encoder_enabled_x
def decode(102), do: :encoder_enabled_y
def decode(103), do: :encoder_enabled_z
@ -168,6 +171,9 @@ defmodule FarmbotFirmware.Param do
def encode(:movement_stall_sensitivity_x), do: 85
def encode(:movement_stall_sensitivity_y), do: 86
def encode(:movement_stall_sensitivity_z), do: 87
def encode(:movement_microsteps_x), do: 91
def encode(:movement_microsteps_y), do: 92
def encode(:movement_microsteps_z), do: 93
def encode(:encoder_enabled_x), do: 101
def encode(:encoder_enabled_y), do: 102
def encode(:encoder_enabled_z), do: 103
@ -396,6 +402,15 @@ defmodule FarmbotFirmware.Param do
def to_human(:movement_stall_sensitivity_z, value),
do: {"stall sensitivity, z-axis", nil, format_float(value)}
def to_human(:movement_microsteps_x, value),
do: {"microsteps, x-axis", nil, format_float(value)}
def to_human(:movement_microsteps_y, value),
do: {"microsteps, y-axis", nil, format_float(value)}
def to_human(:movement_microsteps_z, value),
do: {"microsteps, z-axis", nil, format_float(value)}
def to_human(:encoder_enabled_x, value),
do: {"enable encoders, x-axis", nil, format_bool(value)}

View File

@ -1,5 +1,9 @@
defmodule FarmbotFirmware.Request do
@moduledoc false
# sister module to FarmbotFirmware.Command
# see docs for FarmbotFirmware.request/1
alias FarmbotFirmware
alias FarmbotFirmware.GCODE

View File

@ -1,4 +1,4 @@
defmodule FarmbotFirmware.UARTTransport.Reset do
defmodule FarmbotFirmware.Reset do
@moduledoc """
Behaviour to reset the UART connection into
bootloader mode for firmware upgrades.

View File

@ -11,6 +11,7 @@ defmodule FarmbotFirmware.SideEffects do
@callback load_params :: [{Param.t(), float() | nil}]
@callback handle_position(x: float(), y: float(), z: float()) :: any()
@callback handle_load(x: float(), y: float(), z: float()) :: any()
@callback handle_position_change([{axis(), float()}]) :: any()
@callback handle_encoders_scaled(x: float(), y: float(), z: float()) :: any()
@callback handle_encoders_raw(x: float(), y: float(), z: float()) :: any()

View File

@ -105,6 +105,9 @@ defmodule FarmbotFirmware.StubSideEffects do
@impl SideEffects
def handle_position(_), do: :noop
@impl SideEffects
def handle_load(_), do: :noop
@impl SideEffects
def handle_position_change(_), do: :noop

View File

@ -14,8 +14,9 @@ defmodule FarmbotFirmware.UARTTransport do
def init(args) do
device = Keyword.fetch!(args, :device)
handle_gcode = Keyword.fetch!(args, :handle_gcode)
reset = Keyword.fetch!(args, :reset)
{:ok, uart} = UART.start_link()
{:ok, %{uart: uart, device: device, open: false, handle_gcode: handle_gcode}, 0}
{:ok, %{uart: uart, device: device, open: false, handle_gcode: handle_gcode, reset: reset}, 0}
end
def terminate(_, state) do
@ -26,7 +27,7 @@ defmodule FarmbotFirmware.UARTTransport do
opts = [active: true, speed: 115_200, framing: {UART.Framing.Line, separator: "\r\n"}]
with :ok <- open(state.uart, state.device, opts),
:ok <- reset(state.uart, state.device, opts) do
:ok <- reset(state) do
{:noreply, %{state | open: true}}
else
{:error, reason} ->
@ -51,8 +52,8 @@ defmodule FarmbotFirmware.UARTTransport do
{:reply, r, state}
end
def reset(_uart_pid, _device_path, _opts) do
if module = config()[:reset] do
def reset(state) do
if module = state[:reset] do
module.reset()
else
:ok
@ -62,8 +63,4 @@ defmodule FarmbotFirmware.UARTTransport do
def open(uart_pid, device_path, opts) do
UART.open(uart_pid, device_path, opts)
end
defp config do
Application.get_env(:farmbot_firmware, __MODULE__)
end
end

View File

@ -19,6 +19,7 @@ defmodule FarmbotFirmware.MixProject do
elixirc_options: [warnings_as_errors: true, ignore_module_conflict: true],
arduino_commit: arduino_commit(),
start_permanent: Mix.env() == :prod,
deps: deps(),
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
test: :test,
@ -28,7 +29,12 @@ defmodule FarmbotFirmware.MixProject do
"coveralls.post": :test,
"coveralls.html": :test
],
deps: deps()
source_url: "https://github.com/Farmbot/farmbot_os",
homepage_url: "http://farmbot.io",
docs: [
logo: "../farmbot_os/priv/static/farmbot_logo.png",
extras: Path.wildcard("../docs/**/*.md")
]
]
end
@ -43,10 +49,10 @@ defmodule FarmbotFirmware.MixProject do
defp deps do
[
{:farmbot_telemetry, path: "../farmbot_telemetry", env: Mix.env()},
{:circuits_uart, "~> 1.3"},
{:circuits_uart, "~> 1.4.0"},
{:excoveralls, "~> 0.10", only: [:test], targets: [:host]},
{:dialyxir, "~> 1.0.0-rc.3", only: [:dev], targets: [:host], runtime: false},
{:ex_doc, "~> 0.19", only: [:dev], targets: [:host], runtime: false}
{:ex_doc, "~> 0.21.2", only: [:dev], targets: [:host], runtime: false}
]
end
end

View File

@ -1,6 +1,6 @@
%{
"certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"circuits_uart": {:hex, :circuits_uart, "1.3.2", "206579d28fcd443881777fadf5ee6af1ea7835a7ccd352b54d73e98ea5266b4c", [:mix], [{:elixir_make, "~> 0.5", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"circuits_uart": {:hex, :circuits_uart, "1.4.0", "799abad2d5f355bd571c46de089e62c6341e6b08f9fdf51f4d53d50f5d5bbda9", [:mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.5.0", "4ef3ae066ee10fe01ea3272edc8f024347a0d3eb95f6fbb9aed556dacbfc1337", [:rebar3], [{:cowlib, "~> 2.6.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.6.2", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
@ -8,25 +8,25 @@
"db_connection": {:hex, :db_connection, "1.1.3", "89b30ca1ef0a3b469b1c779579590688561d586694a3ce8792985d4d7e575a61", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "1.0.0-rc.4", "71b42f5ee1b7628f3e3a6565f4617dfb02d127a0499ab3e72750455e986df001", [:mix], [{:erlex, "~> 0.1", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.2.6", "b6da42b3831458d3ecc57314dff3051b080b9b2be88c2e5aa41cd642a5b044ed", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.2.9", "031d55df9bb430cb118e6f3026a87408d9ce9638737bda3871e5d727a3594aae", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
"erlex": {:hex, :erlex, "0.1.6", "c01c889363168d3fdd23f4211647d8a34c0f9a21ec726762312e08e083f3d47e", [:mix], [], "hexpm"},
"esqlite": {:hex, :esqlite, "0.2.4", "3a8a352c190afe2d6b828b252a6fbff65b5cc1124647f38b15bdab3bf6fd4b3e", [:rebar3], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.1", "519bb9c19526ca51d326c060cb1778d4a9056b190086a8c6c115828eaccea6cf", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.7", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.21.2", "caca5bc28ed7b3bdc0b662f8afe2bee1eedb5c3cf7b322feeeb7c6ebbde089d6", [:mix], [{:earmark, "~> 1.3.3 or ~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.10.2", "fb4abd5b8a1b9d52d35e1162e7e2ea8bfb84b47ae07c38d39aa8ce64be0b0794", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"},
"gen_stage": {:hex, :gen_stage, "0.14.1", "9d46723fda072d4f4bb31a102560013f7960f5d80ea44dcb96fd6304ed61e7a4", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.16.0", "4a7e90408cef5f1bf57c5a39e2db8c372a906031cc9b1466e963101cb927dafc", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.14.3", "b5f6f5dcc4f1fba340762738759209e21914516df6be440d85772542d4a5e412", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"makeup": {:hex, :makeup, "0.5.5", "9e08dfc45280c5684d771ad58159f718a7b5788596099bdfb0284597d368a882", [:mix], [{:nimble_parsec, "~> 0.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.10.0", "0f09c2ddf352887a956d84f8f7e702111122ca32fbbc84c2f0569b8b65cbf7fa", [:mix], [{:makeup, "~> 0.5.5", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"makeup": {:hex, :makeup, "1.0.0", "671df94cf5a594b739ce03b0d0316aa64312cee2574b6a44becb83cd90fb05dc", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.0", "5e8d45a39e95c650900d03f897fbf99ae04f60ab1daa4a34c7a20a5151b7a5fe", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
"nerves_uart": {:hex, :nerves_uart, "1.2.0", "195424116b925cd3bf9d666be036c2a80655e6ca0f8d447e277667a60005c50e", [:mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.4.0", "ee261bb53214943679422be70f1658fff573c5d0b0a1ecd0f18738944f818efe", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_cowboy": {:hex, :plug_cowboy, "2.0.0", "ab0c92728f2ba43c544cce85f0f220d8d30fc0c90eaa1e6203683ab039655062", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
@ -37,7 +37,7 @@
"sqlite_ecto2": {:hex, :sqlite_ecto2, "2.3.1", "fe58926854c3962c4c8710bd1070dd4ba3717ba77250387794cb7a65f77006aa", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "2.2.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.13", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: false]}, {:sqlitex, "~> 1.4", [hex: :sqlitex, repo: "hexpm", optional: false]}], "hexpm"},
"sqlitex": {:hex, :sqlitex, "1.4.3", "a50f12d6aeb25f4ebb128453386c09bbba8f5abd3c7713dc5eaa92f359926ac5", [:mix], [{:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.4", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
"timex": {:hex, :timex, "3.4.2", "d74649c93ad0e12ce5b17cf5e11fbd1fb1b24a3d114643e86dba194b64439547", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "0.5.19", "7962a3997bf06303b7d1772988ede22260f3dae1bf897408ebdac2b4435f4e6a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},

File diff suppressed because it is too large Load Diff

View File

@ -39,8 +39,14 @@ defmodule FarmbotFirmware.GCODETest do
end
test "error" do
assert {nil, {:report_error, []}} = GCODE.decode("R03")
assert {"100", {:report_error, []}} = GCODE.decode("R03 Q100")
assert {nil, {:report_error, [:no_error]}} = GCODE.decode("R03")
assert {nil, {:report_error, [:no_error]}} = GCODE.decode("R03 V0")
assert {nil, {:report_error, [:emergency_lock]}} = GCODE.decode("R03 V1")
assert {nil, {:report_error, [:timeout]}} = GCODE.decode("R03 V2")
assert {nil, {:report_error, [:stall_detected]}} = GCODE.decode("R03 V3")
assert {nil, {:report_error, [:invalid_command]}} = GCODE.decode("R03 V14")
assert {nil, {:report_error, [:no_config]}} = GCODE.decode("R03 V15")
assert {"100", {:report_error, [:no_error]}} = GCODE.decode("R03 Q100")
assert "R03" = GCODE.encode({nil, {:report_error, []}})
assert "R03 Q100" = GCODE.encode({"100", {:report_error, []}})

View File

@ -66,6 +66,17 @@ config :farmbot, FarmbotOS.Platform.Supervisor,
FarmbotOS.Platform.Host.Configurator
]
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotFirmware.NullReset
config :logger,
handle_sasl_reports: false,
handle_otp_reports: false,
compile_time_purge_matching: [
[application: :amqp],
[application: :amqp_client],
[application: :rabbit_common]
]
import_config("lagger.exs")
if Mix.target() == :host do

View File

@ -2,10 +2,9 @@ use Mix.Config
config :farmbot_core, FarmbotCore.FirmwareTTYDetector, expected_names: ["ttyUSB0", "ttyAMA0"]
config :farmbot_firmware, FarmbotFirmware.UARTTransport,
reset: FarmbotOS.Platform.Target.FirmwareReset.GPIO
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotOS.Platform.Target.FirmwareReset.GPIO
config :farmbot, FarmbotOS.Init.Supervisor,
init_children: [
FarmbotOS.Platform.Target.FirmwareReset.GPIO
FarmbotOS.Platform.Target.RTCWorker
]

View File

@ -4,10 +4,9 @@ config :farmbot_core, FarmbotCore.FirmwareTTYDetector, expected_names: ["ttyUSB0
config :farmbot_core, FarmbotCore.FirmwareOpenTask, attempt_threshold: 50
config :farmbot_firmware, FarmbotFirmware.UARTTransport,
reset: FarmbotOS.Platform.Target.FirmwareReset.GPIO
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotOS.Platform.Target.FirmwareReset.GPIO
config :farmbot, FarmbotOS.Init.Supervisor,
init_children: [
FarmbotOS.Platform.Target.FirmwareReset.GPIO
FarmbotOS.Platform.Target.RTCWorker
]

View File

@ -2,7 +2,9 @@ use Mix.Config
config :farmbot_core, FarmbotCore.FirmwareTTYDetector, expected_names: ["ttyUSB0", "ttyACM0"]
config :farmbot_firmware, FarmbotFirmware.UARTTransport,
reset: FarmbotOS.Platform.Target.FirmwareReset.NULL
config :farmbot_firmware, FarmbotFirmware, reset: FarmbotFirmware.NullReset
config :farmbot, FarmbotOS.Init.Supervisor, init_children: []
config :farmbot, FarmbotOS.Init.Supervisor,
init_children: [
FarmbotOS.Platform.Target.RTCWorker
]

View File

@ -4,6 +4,7 @@ defmodule Avrdude do
"""
@uart_speed 115_200
require FarmbotCore.Logger
@spec flash(Path.t(), Path.t(), (() -> :ok)) :: {number, any()}
def flash(hex_path, tty_path, reset_fun) do
@ -28,7 +29,22 @@ defmodule Avrdude do
]
# call the function for resetting the line before executing avrdude.
:ok = reset_fun.()
MuonTrap.cmd("avrdude", args, into: IO.stream(:stdio, :line))
call_reset_fun(reset_fun)
MuonTrap.cmd("avrdude", args, into: IO.stream(:stdio, :line), stderr_to_stdout: true)
end
def call_reset_fun(reset_fun) do
try do
reset_fun.()
catch
error_type, error ->
FarmbotCore.Logger.error(1, """
Error calling reset function: #{inspect(reset_fun)}
error type: #{error_type}
error: #{inspect(error)}
""")
end
end
:ok
end

View File

@ -1,4 +1,9 @@
defmodule FarmbotOS.Configurator.ConfigDataLayer do
@moduledoc """
implementation of Configurator.DataLayer responsible for
gathering and storing data Via Ecto.
"""
@behaviour FarmbotOS.Configurator.DataLayer
require FarmbotCore.Logger
alias FarmbotCore.Config

View File

@ -1,4 +1,8 @@
defmodule FarmbotOS.Configurator.DataLayer do
@moduledoc """
intermediate layer for stubbing configuration data
"""
# "net_config_dns_name" => String.t()
# "net_config_ntp1" => String.t()
# "net_config_ntp2" => String.t()
@ -22,9 +26,18 @@ defmodule FarmbotOS.Configurator.DataLayer do
required(String.t()) => nil | String.t()
}
@doc "check if the most resent reboot was caused for an exceptional reason"
@callback load_last_reset_reason() :: nil | String.t()
@doc "load the email from the configuration store"
@callback load_email() :: nil | String.t()
@doc "load the password from the configuration store"
@callback load_password() :: nil | String.t()
@doc "load the server from the configuration store"
@callback load_server() :: nil | String.t()
@doc "save the configuration data to the configuration store"
@callback save_config(conf) :: any()
end

View File

@ -1,4 +1,11 @@
defmodule FarmbotOS.Configurator.DetsTelemetryLayer do
@moduledoc """
Telemetry layer implementation for fetching telemetry data from
`farmbot_telemetry` OTP application.
Still a work in progress.
"""
@behaviour FarmbotOS.Configurator.TelemetryLayer
@impl FarmbotOS.Configurator.TelemetryLayer

View File

@ -1,4 +1,8 @@
defmodule FarmbotOS.Configurator.FakeNetworkLayer do
@moduledoc """
stub Configurator network layer
"""
@behaviour FarmbotOS.Configurator.NetworkLayer
@impl FarmbotOS.Configurator.NetworkLayer

View File

@ -1,17 +1,25 @@
defmodule FarmbotOS.Configurator.LoggerSocket do
@moduledoc """
WebSocket handler for streaming logs
"""
alias FarmbotOS.Configurator.LoggerSocket.LoggerBackend
require Logger
@behaviour :cowboy_websocket
@impl :cowboy_websocket
def init(req, state) do
{:cowboy_websocket, req, state}
end
@impl :cowboy_websocket
def websocket_init(_state) do
send(self(), :after_connect)
{:ok, %{}}
end
@impl :cowboy_websocket
def websocket_handle({:text, message}, state) do
case Jason.decode(message) do
{:ok, json} ->
@ -23,6 +31,7 @@ defmodule FarmbotOS.Configurator.LoggerSocket do
end
end
@impl :cowboy_websocket
def websocket_info(:after_connect, state) do
Logger.add_backend(LoggerBackend)
LoggerBackend.register()
@ -70,6 +79,7 @@ defmodule FarmbotOS.Configurator.LoggerSocket do
{:ok, state}
end
@impl :cowboy_websocket
def terminate(_reason, _req, _state) do
:ok
end

Some files were not shown because too many files have changed in this diff Show More