In the beginning of the pandemic, the company offices went closed rather quickly and I found myself working with my laptop placed on a piano. The initial shock held for a long time, I spent couple of months working like that. This was not good for my posture (mental and physical) at all.
Later on, I built a very nice setup around motorized standing desk with all the bells and whistles - quite meticulous cable management, custom oak wooden top (expensive), BenQ LED light placed on external display, IKEA pegboard on the wall next to the table to hold the essentials (like noise cancelling headphones, pens, SPARC assembly cheat-sheet, etc.), Varmilo keyboard Keychron keyboard, Grovemade desk pad, WiFi extender AP mounted underneath the desk, professionally framed pictures/drawings on the wall, a small plant, etc.
Using this setup allowed me to be very productive, possibly more productive than in the office, to the point when I wanted to know more about how I work to make the increased productivity levels sustainable.
When shopping around for parts of another project on Adafruit, I remembered an interesting presentation from GrafanaCon 2021 called WFH habits during lockdown told by Grafana where the presenter used sensor paired with Grafana to monitor her WFH behavior w.r.t. breaks etc. This made me throw some more stuff to the Adafruit order, scavenge some parts laying around and make my own version of work habits monitoring setup.
My goal is to provide the following functionality:
This is the 2nd version. See below for older versions.
The blinking of the neopixel is prioritized so that it will blink with the color corresponding to the highest priority alert.
Originally, this was based on a Raspberry Pi with a directly attached USB hub to connect the distance reader and a light bulb with 3 lights which was used to do the alerting. The ultrasonic distance sensor was placed in original iPhone plastic box (the one with the transparent cover) with two holes for the sensor. The Rpi died suddenly and I found more fun "architecture" based on microcontrollers.
Also, I believe the placement of the distance sensor was causing value flapping. It was attached with double sticky tape the white cable holder underneath the table on the right side and was not fully in horizontal position which is possibly made it to get erroneous readings. Another possibility is some interaction with the Linux running on the Raspberry Pi.
The code assumes there is NTP server running and responding on the default IPv4 gateway.
Install the Tapo app on a mobile phone. Register new account, remember the user ID and password as these will be necessary. Allow third-party API access within the app. This is necessary to get the current power reading via API working.
Setup the plug so that it connects to dedicated (IoT) WiFi network with IP address staticly assigned via DHCP. This is needed to be able to read the power consumption values using the same host/IP hard-coded in the configuration.
Set up and configure https://github.com/vladak/plug2mqtt/ somewhere on the IoT network (say on a Raspberry Pi) to publish the state of the plug, notably the power consumption.
Solder the US-100 (in UART mode) per the US-100 guide.
The Prometheus configuration needs to have the bits for the above mentioned pre-requisites.
For the table distance the MQTT exporter configuration in /etc/prometheus/mqtt-exporter.yaml needs to be augmented
with this section:
metrics:
-
# The name of the metric in prometheus
prom_name: distance
# The name of the metric in a MQTT JSON message
mqtt_name: distance
# The prometheus help text for this metric
help: distance
# The prometheus type for this metric. Valid values are: "gauge" and "counter"
type: gauge
Assumes the Prometheus data source is already set up.
Perform the following setup on the Grafana server:
Here is list of tunables. Most of these are mandatory.
| Purpose | Name |
|---|---|
ntp_server | hostname or IP address of NTP server. If left not configured, the default router will be used. |
tz_offset | time zone offset, default 1. |
SSID | WiFi SSID |
password | WiFi password |
broker | MQTT broker IP address |
broker_port | MQTT broker port |
log_level | log level (e.g. "info" or "debug") |
mqtt_topic_env | MQTT topic to subscribe for environmental metrics |
mqtt_topic_power | MQTT topic to subscribe for power state of the display |
mqtt_topic | MQTT topic to publish data to (e.g. table state) |
distance_threshold | threshold for table distance from the ground (to infer whether table is up or down), in centimeters |
power_threshold_watts | threshold for the power consumption of the display (to infer whether the display is on or off), in Watts |
co2_threshold | CO2 threshold for alerting, in PPM |
last_update_threshold | when no data is received within this threshold, display N/A, in seconds |
break_threshold_seconds | if the display is considered to be on for more than this time duration, make an alert, in seconds |
icon_paths | paths to the icon files (array of 2 paths - the first is the default, the second is displayed when the table has been in given state for more than the threshold below) |
table_state_dur_threshold | the duration for table alerting, in seconds |
start_hr | hour (24 hr format) after which the TFT display should be on (inclusive) |
end_hr | hour (24 hr format) after which the TFT display should be off (exclusive) |
font_file_name | path to the font file |
Example secrets.py configuration:
secrets = {
"SSID": "FOO",
"password": "XYZ",
"broker": "172.40.0.3",
"broker_port": 1883,
"log_level": "info",
"mqtt_topic_env": "devices/pracovna/qtpy",
"mqtt_topic_power": "devices/plug/pracovna",
"mqtt_topic": "devices/pracovna/featherTFT",
"distance_threshold": 90,
"power_threshold_watts": 35,
"co2_threshold": 1000,
"last_update_threshold": 60,
"break_threshold_seconds": 2700,
"icon_paths": [
"/images/icons8-totoro-120.bmp",
"/images/icons8-totoro-120-umbrella.bmp",
],
"table_state_dur_threshold": 1800,
"start_hr": 8,
"end_hr": 23,
"font_file_name": "fonts/Inter-Regular-25.pcf",
}
It assumes there are 2 120x96 images in the images directory. It will do fine without them, however the table position alerting will resort just to blinking the diode.
With circup installed and the Feather connected over USB (assuming Linux distro):
circup install -r requirements.txt
cp -R images/ fonts/ *.py settings.toml /media/$USER/CIRCUITPY/
Using bitmap fonts makes the display more readable and nicer. Also, some of the glyps like the circle in °C can be actually displayed. The font however has to be converted to fit onto the flash and then it has to be used in a special way for quick display.
extras/ttf/Inter-Regular.ttf into BDF (use 25 pixels size) using https://fontforge.github.io/CIRCUITPY directorysafemode.py and drive on, esp. for these non-critical projects.294 commits
Python
100.0%
In the beginning of the pandemic, the company offices went closed rather quickly and I found myself working with my laptop placed on a piano. The initial shock held for a long time, I spent couple of months working like that. This was not good for my posture (mental and physical) at all.
Later on, I built a very nice setup around motorized standing desk with all the bells and whistles - quite meticulous cable management, custom oak wooden top (expensive), BenQ LED light placed on external display, IKEA pegboard on the wall next to the table to hold the essentials (like noise cancelling headphones, pens, SPARC assembly cheat-sheet, etc.), Varmilo keyboard Keychron keyboard, Grovemade desk pad, WiFi extender AP mounted underneath the desk, professionally framed pictures/drawings on the wall, a small plant, etc.
Using this setup allowed me to be very productive, possibly more productive than in the office, to the point when I wanted to know more about how I work to make the increased productivity levels sustainable.
When shopping around for parts of another project on Adafruit, I remembered an interesting presentation from GrafanaCon 2021 called WFH habits during lockdown told by Grafana where the presenter used sensor paired with Grafana to monitor her WFH behavior w.r.t. breaks etc. This made me throw some more stuff to the Adafruit order, scavenge some parts laying around and make my own version of work habits monitoring setup.
My goal is to provide the following functionality:
This is the 2nd version. See below for older versions.
The blinking of the neopixel is prioritized so that it will blink with the color corresponding to the highest priority alert.
Originally, this was based on a Raspberry Pi with a directly attached USB hub to connect the distance reader and a light bulb with 3 lights which was used to do the alerting. The ultrasonic distance sensor was placed in original iPhone plastic box (the one with the transparent cover) with two holes for the sensor. The Rpi died suddenly and I found more fun "architecture" based on microcontrollers.
Also, I believe the placement of the distance sensor was causing value flapping. It was attached with double sticky tape the white cable holder underneath the table on the right side and was not fully in horizontal position which is possibly made it to get erroneous readings. Another possibility is some interaction with the Linux running on the Raspberry Pi.
The code assumes there is NTP server running and responding on the default IPv4 gateway.
Install the Tapo app on a mobile phone. Register new account, remember the user ID and password as these will be necessary. Allow third-party API access within the app. This is necessary to get the current power reading via API working.
Setup the plug so that it connects to dedicated (IoT) WiFi network with IP address staticly assigned via DHCP. This is needed to be able to read the power consumption values using the same host/IP hard-coded in the configuration.
Set up and configure https://github.com/vladak/plug2mqtt/ somewhere on the IoT network (say on a Raspberry Pi) to publish the state of the plug, notably the power consumption.
Solder the US-100 (in UART mode) per the US-100 guide.
The Prometheus configuration needs to have the bits for the above mentioned pre-requisites.
For the table distance the MQTT exporter configuration in /etc/prometheus/mqtt-exporter.yaml needs to be augmented
with this section:
metrics:
-
# The name of the metric in prometheus
prom_name: distance
# The name of the metric in a MQTT JSON message
mqtt_name: distance
# The prometheus help text for this metric
help: distance
# The prometheus type for this metric. Valid values are: "gauge" and "counter"
type: gauge
Assumes the Prometheus data source is already set up.
Perform the following setup on the Grafana server:
Here is list of tunables. Most of these are mandatory.
| Purpose | Name |
|---|---|
ntp_server | hostname or IP address of NTP server. If left not configured, the default router will be used. |
tz_offset | time zone offset, default 1. |
SSID | WiFi SSID |
password | WiFi password |
broker | MQTT broker IP address |
broker_port | MQTT broker port |
log_level | log level (e.g. "info" or "debug") |
mqtt_topic_env | MQTT topic to subscribe for environmental metrics |
mqtt_topic_power | MQTT topic to subscribe for power state of the display |
mqtt_topic | MQTT topic to publish data to (e.g. table state) |
distance_threshold | threshold for table distance from the ground (to infer whether table is up or down), in centimeters |
power_threshold_watts | threshold for the power consumption of the display (to infer whether the display is on or off), in Watts |
co2_threshold | CO2 threshold for alerting, in PPM |
last_update_threshold | when no data is received within this threshold, display N/A, in seconds |
break_threshold_seconds | if the display is considered to be on for more than this time duration, make an alert, in seconds |
icon_paths | paths to the icon files (array of 2 paths - the first is the default, the second is displayed when the table has been in given state for more than the threshold below) |
table_state_dur_threshold | the duration for table alerting, in seconds |
start_hr | hour (24 hr format) after which the TFT display should be on (inclusive) |
end_hr | hour (24 hr format) after which the TFT display should be off (exclusive) |
font_file_name | path to the font file |
Example secrets.py configuration:
secrets = {
"SSID": "FOO",
"password": "XYZ",
"broker": "172.40.0.3",
"broker_port": 1883,
"log_level": "info",
"mqtt_topic_env": "devices/pracovna/qtpy",
"mqtt_topic_power": "devices/plug/pracovna",
"mqtt_topic": "devices/pracovna/featherTFT",
"distance_threshold": 90,
"power_threshold_watts": 35,
"co2_threshold": 1000,
"last_update_threshold": 60,
"break_threshold_seconds": 2700,
"icon_paths": [
"/images/icons8-totoro-120.bmp",
"/images/icons8-totoro-120-umbrella.bmp",
],
"table_state_dur_threshold": 1800,
"start_hr": 8,
"end_hr": 23,
"font_file_name": "fonts/Inter-Regular-25.pcf",
}
It assumes there are 2 120x96 images in the images directory. It will do fine without them, however the table position alerting will resort just to blinking the diode.
With circup installed and the Feather connected over USB (assuming Linux distro):
circup install -r requirements.txt
cp -R images/ fonts/ *.py settings.toml /media/$USER/CIRCUITPY/
Using bitmap fonts makes the display more readable and nicer. Also, some of the glyps like the circle in °C can be actually displayed. The font however has to be converted to fit onto the flash and then it has to be used in a special way for quick display.
extras/ttf/Inter-Regular.ttf into BDF (use 25 pixels size) using https://fontforge.github.io/CIRCUITPY directorysafemode.py and drive on, esp. for these non-critical projects.294 commits
Python
100.0%