Urgent
- Network config in UI
- On-screen keyboard for pi kiosk
- Installation system for less technical users
- Adjust the device code to be more testable and write tests
- Alarm or alert system for when the time series device data diverges "too far"
- Bug in history live chart that causes re-rendering artifacts
- Fix existing tests
- Elixir release for the app
- UI timer for "last updated xxx ago..."
- Tests for the phoenix-y parts
- Add the
Cookscontext - Time series data for cooks
Not So Urgent
- Virtual field in devices to support offline/online flag
- Support devices other than Egg Genius
- Reorganize documentation
- Stop Cook button for quick, common, change to a cook
- Some sort of automated installer or instructions
- Update the main app to be less "here's you're phoenix skeleton" and more "here's Open Boss"
- Better github integration
- UI graphs for time series device data
- Homebrew
# Note: if you are on MacOS, you will need XCode or gcc also
brew install openssl ncurses- Ubuntu & other Debian-derived (incl. Raspberry Pi OS)
sudo apt-get install -y build-essential make autoconf libssl-dev libncurses-dev- Add plugins for ASDF and install the tools:
cd open_boss
asdf plugin-add elixir
asdf plugin-add erlang
asdf plugin-add nodejs
asdf install- One-time Elixir and Erlang language setup
mix archive.install hex nerves_bootstrap
mix local.hex
mix local.rebar- Get deps and make sure tests run successfully
mix deps.get
mix test- Build static assets (only needed when they change)
mix assets.deployNerves uses MIX_TARGET=host to allow standard Elixir development, but eventually the code
should be tested on the target. There is a good deal of interplay between the files in
config/*.exs for this; but in general, you insert a micro SD card into your laptop
and run:
MIX_ENV=prod MIX_TARGET=rpi4 mix do deps.get, firmware, burnFor the koisk build, which is meant to work with the Pi Touchscreen, use:
MIX_ENV=prod MIX_TARGET=rpi4_kiosk mix do deps.get, firmware, burnOnce you have a working target device, you can build and update the firmware remotely in one step with:
MIX_TARGET=rpi4_kiosk MIX_ENV=prod "$SHELL" -c 'mix firmware && ./upload.sh open-boss.local'https://github.com/nerves-project/nerves_system_x86_64?tab=readme-ov-file#running-in-qemu
Build firmware, make a raw disk, install firmware, and boot it up. Web server will be http://localhost:4000/.
Use poweroff from iex shell to cleanly shut down:
MIX_TARGET=x86_64 MIX_ENV=prod mix firmware
qemu-img create -f raw disk.img 1G
fwup -d disk.img _build/x86_64_prod/nerves/images/open_boss.fw
qemu-system-x86_64 -drive file=disk.img,if=virtio,format=raw -net nic,model=virtio -net user,hostfwd=tcp::10022-:22,hostfwd=tcp::4000-:80 -nographic -serial mon:stdio -m 1024Put it all together with a build and upgrade:
MIX_TARGET=x86_64 MIX_ENV=prod mix firmware && MIX_TARGET=x86_64 MIX_ENV=prod SSH_OPTIONS="-p 10022" ./upload.sh localhostExample output from VintegeNet.get_by_prefix([]) on a raspberry pi 4:
[
{["available_interfaces"], ["wlan0"]},
{["connection"], :internet},
{["interface", "eth0", "config"],
%{type: VintageNetEthernet, ipv4: %{method: :dhcp}}},
{["interface", "eth0", "connection"], :disconnected},
{["interface", "eth0", "hw_path"], "/devices/platform/scb/fd580000.ethernet"},
{["interface", "eth0", "lower_up"], false},
{["interface", "eth0", "mac_address"], "dc:a6:32:22:07:ff"},
{["interface", "eth0", "present"], true},
{["interface", "eth0", "state"], :configured},
{["interface", "eth0", "type"], VintageNetEthernet},
{["interface", "lo", "addresses"],
[
%{
scope: :host,
netmask: {65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535},
family: :inet6,
address: {0, 0, 0, 0, 0, 0, 0, 1},
prefix_length: 128
},
%{
scope: :host,
netmask: {255, 0, 0, 0},
family: :inet,
address: {127, 0, 0, 1},
prefix_length: 8
}
]},
{["interface", "lo", "hw_path"], "/devices/virtual"},
{["interface", "lo", "lower_up"], true},
{["interface", "lo", "mac_address"], "00:00:00:00:00:00"},
{["interface", "lo", "present"], true},
{["interface", "usb0", "addresses"],
[
%{
scope: :universe,
netmask: {255, 255, 255, 252},
family: :inet,
address: {172, 31, 222, 217},
prefix_length: 30
}
]},
{["interface", "usb0", "config"],
%{type: VintageNetDirect, vintage_net_direct: %{}}},
{["interface", "usb0", "connection"], :disconnected},
{["interface", "usb0", "hw_path"],
"/devices/platform/soc/fe980000.usb/gadget.0"},
{["interface", "usb0", "lower_up"], false},
{["interface", "usb0", "mac_address"], "d2:4a:4b:d2:57:c4"},
{["interface", "usb0", "present"], true},
{["interface", "usb0", "state"], :configured},
{["interface", "usb0", "type"], VintageNetDirect},
{["interface", "wlan", "config"],
%{
type: VintageNetWiFi,
ipv4: %{method: :disabled},
vintage_net_wifi: %{networks: []}
}},
{["interface", "wlan", "connection"], :disconnected},
{["interface", "wlan", "state"], :retrying},
{["interface", "wlan", "type"], VintageNetWiFi},
{["interface", "wlan0", "addresses"],
[
%{
scope: :universe,
netmask: {65535, 65535, 65535, 65535, 0, 0, 0, 0},
family: :inet6,
address: {64786, 22728, 42039, 39756, 56998, 13055, 65058, 2048},
prefix_length: 64
},
%{
scope: :universe,
netmask: {255, 255, 255, 0},
family: :inet,
address: {192, 168, 86, 22},
prefix_length: 24
},
%{
scope: :link,
netmask: {65535, 65535, 65535, 65535, 0, 0, 0, 0},
family: :inet6,
address: {65152, 0, 0, 0, 56998, 13055, 65058, 2048},
prefix_length: 64
}
]},
{["interface", "wlan0", "config"],
%{
type: VintageNetWiFi,
ipv4: %{method: :dhcp},
vintage_net_wifi: %{
networks: [
%{
mode: :infrastructure,
psk: "5703F492927F161B20E5B9AC14582D4988320910519F5A41DF81A0B626EF3F80",
ssid: "Pluto",
key_mgmt: :wpa_psk
}
]
}
}},
{["interface", "wlan0", "connection"], :internet},
{["interface", "wlan0", "dhcp_options"],
%{
broadcast: {192, 168, 86, 255},
domain: "lan",
ip: {192, 168, 86, 22},
mask: 24,
dns: [{192, 168, 86, 1}],
hostname: "open-boss-9d49",
siaddr: {192, 168, 86, 1},
subnet: {255, 255, 255, 0},
router: [{192, 168, 86, 1}],
lease: 86400,
renewal_time: 43200,
rebind_time: 75600,
serverid: {192, 168, 86, 1}
}},
{["interface", "wlan0", "hw_path"],
"/devices/platform/soc/fe300000.mmcnr/mmc_host/mmc1/mmc1:0001/mmc1:0001:1"},
{["interface", "wlan0", "lower_up"], true},
{["interface", "wlan0", "mac_address"], "dc:a6:32:22:08:00"},
{["interface", "wlan0", "present"], true},
{["interface", "wlan0", "state"], :configured},
{["interface", "wlan0", "type"], VintageNetWiFi},
{["interface", "wlan0", "wifi", "access_points"],
[
%VintageNetWiFi.AccessPoint{
bssid: "22:7f:88:1c:53:79",
frequency: 2437,
band: :wifi_2_4_ghz,
channel: 6,
signal_dbm: -34,
signal_percent: 93,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: ""
},
%VintageNetWiFi.AccessPoint{
bssid: "5e:ba:ef:e7:98:89",
frequency: 5745,
band: :wifi_5_ghz,
channel: 149,
signal_dbm: -59,
signal_percent: 88,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :wps, :ess, :p2p],
ssid: "DIRECT-89-HP M283 LaserJet"
},
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:21:fe",
frequency: 2437,
band: :wifi_2_4_ghz,
channel: 6,
signal_dbm: -40,
signal_percent: 89,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
},
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:22:02",
frequency: 5745,
band: :wifi_5_ghz,
channel: 149,
signal_dbm: -46,
signal_percent: 99,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
},
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:39:6e",
frequency: 2462,
band: :wifi_2_4_ghz,
channel: 11,
signal_dbm: -50,
signal_percent: 79,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
},
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:39:72",
frequency: 5745,
band: :wifi_5_ghz,
channel: 149,
signal_dbm: -54,
signal_percent: 93,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
},
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:3e:00",
frequency: 2412,
band: :wifi_2_4_ghz,
channel: 1,
signal_dbm: -35,
signal_percent: 93,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
},
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:3e:04",
frequency: 5745,
band: :wifi_5_ghz,
channel: 149,
signal_dbm: -38,
signal_percent: 100,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
},
%VintageNetWiFi.AccessPoint{
bssid: "f8:f0:05:6d:57:31",
frequency: 2462,
band: :wifi_2_4_ghz,
channel: 11,
signal_dbm: -53,
signal_percent: 75,
flags: [:wpa_psk_ccmp_tkip, :wpa2_psk_ccmp_tkip, :wpa, :psk, :ccmp,
:tkip, :wpa2, :psk, :ccmp, :tkip, :wps, :ess],
ssid: "sparkmeter-N000356"
}
]},
{["interface", "wlan0", "wifi", "clients"], []},
{["interface", "wlan0", "wifi", "current_ap"],
%VintageNetWiFi.AccessPoint{
bssid: "90:ca:fa:98:3e:00",
frequency: 2412,
band: :wifi_2_4_ghz,
channel: 1,
signal_dbm: -35,
signal_percent: 93,
flags: [:wpa2_psk_ccmp, :wpa2, :psk, :ccmp, :ess],
ssid: "Pluto"
}},
{["name_servers"], [%{address: {192, 168, 86, 1}, from: ["wlan0"]}]}
]- Devices self-identify on the network with mDNS as
_flameboss._tcp.local - Send a HTTP GET request to
/switchto cause the device to enter "Flame Boss Protocol"; it is currently unknown what this really does, but the official iOS app does it and so shall Open Boss - MQTT is used as a pub/sub message bus
- The MQTT topics are
flameboss/<DEVICE_SERIAL_NUMBER>/... - Temperatures are degrees celsius * 10, so 1489 is 148.9 degrees C
- Temperature values range from -32767 to 32768 so it's probably a 16-bit integer
- Blower values are percentage * 100, so 10000 is 100%
- Publish to
flameboss/<DEVICE_SERIAL_NUMBER>/recv - Receive from
flameboss/<DEVICE_SERIAL_NUMBER>/send, though there are other active topics - Data payloads are JSON that has been binary encoded as hexadecimal
- The data payload seems to always have a
namekey that identifies the shape and purpose of the payload - The temps array looks like this:
[-32767,200,-32767,-32767]
^^^^^^ probably meat probe #2
^^^^^^ probably pit probe #2
^^^ meat probe #1
^^^^^^ pit probe #1
These are sent to the device (it is the receiver). They need to be binary encoded JSON as well.
Set temp to flameboss/<DEVICE_SERIAL_NUMBER>/recv
{
"name": "set_temp",
"value": 1489
}These are received from the device (it is the sender)
Device ID from flameboss/<DEVICE_SERIAL_NUMBER>/send/data
{
"device_id": 0,
"disabled": false,
"hw_id": 10,
"name": "id",
"pin": 4257,
"uid": "pOV8rD3sAAAAAAAAAAAAAA=="
}Report temperatures from flameboss/<DEVICE_SERIAL_NUMBER>/send/open
{
"name": "temps",
"cook_id": 0,
"sec": 1732981927,
"temps": [-32767, 200, -32767, -32767],
"set_temp": 1489,
"blower": 0
}