commit
398f15c452
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
|
@ -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",
|
||||
|
|
10
Makefile
10
Makefile
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
```
|
43
docs/SSH.md
43
docs/SSH.md
|
@ -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.
|
|
@ -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`|
|
||||
|
|
|
@ -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")`
|
|
@ -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: []}
|
||||
]
|
||||
}
|
||||
```
|
||||
```
|
|
@ -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
|
|
@ -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
|
||||
```
|
|
@ -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)
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||
```
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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} ->
|
||||
|
|
|
@ -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}}}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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, []}})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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)"
|
||||
|
||||
|
|
|
@ -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)}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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, []}})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
|
@ -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
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
defmodule FarmbotOS.Configurator.FakeNetworkLayer do
|
||||
@moduledoc """
|
||||
stub Configurator network layer
|
||||
"""
|
||||
|
||||
@behaviour FarmbotOS.Configurator.NetworkLayer
|
||||
|
||||
@impl FarmbotOS.Configurator.NetworkLayer
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue