# msv-clubhouse-node - Work in progress ! - Technical demo ## Overview ![architecture diagram](doc/architecture.png) ## Hardware ## - [ESP32 LoRa 868MHz OLED DevBoard](https://de.aliexpress.com/item/33018609928.html) - [Bosch BMP280](https://de.aliexpress.com/item/1005003406725433.html) - [Reed Switch](https://de.aliexpress.com/item/1005004549803034.html) - [Wind speed sensor](https://de.aliexpress.com/item/1005001330214766.html) - [Wind direction sensor](https://de.aliexpress.com/item/4000590284491.html) ## Register Device at TTN 0. Register manually a device. 1. Frequency plan Europe 863-870 MHz (SF9 for RX2 - recommended) 2. LoRaWAN version LoRaWAN Specification 1.0.2 3. Regional Parameters version RP001 Regional Parameters 1.0.2 4. JoinEUI all zeros 5. Generate keys ## Build Node Firmware 0. Clone repo 1. Init GIT-submodules ``` git submodule init git submodule update ``` 2. Set following defines via menuconfig: ``` AppEUI DevEUI AppKey TTN LoRa frequency / region ``` 3. Build with ESP-IDF extension in VSCodium ## MQTT Endpoint ## `pip3 install paho-mqtt` - `mkdir /opt/msv-clubhouse-backend/` - `cd /opt/msv-clubhouse-backend/` - import `msv_clubhouse_backend.py` and `config.py` - Set the constants in `config.py` - `chmod +x /opt/msv-clubhouse-backend/msv_clubhouse_backend.py` - `chown -R prometheus /opt/msv-clubhouse-backend/` - `nano /etc/systemd/system/msv-clubhouse-backend.service` - `systemctl daemon-reload && systemctl enable --now msv-clubhouse-backend.service` ## JS Payload Formatter ``` function Decoder(bytes, port) { var decoded = {}; // temperature rawTemp = bytes[0] + bytes[1] * 256; decoded.degreesC = sflt162f(rawTemp) * 100; // pressure rawPressure = bytes[2] + bytes[3] * 256; decoded.pressure = sflt162f(rawPressure) * 100; // windspeed rawWindspeed = bytes[4] + bytes[5] * 256; decoded.windspeed = sflt162f(rawWindspeed) * 100; // winddirection rawWinddirection = bytes[6] + bytes[7] * 256; decoded.winddirection = sflt162f(rawWinddirection) * 100; if(bytes[8] === 0){ decoded.dooropen = false; }else{ decoded.dooropen = true; } return decoded; } function sflt162f(rawSflt16) { // rawSflt16 is the 2-byte number decoded from wherever; // it's in range 0..0xFFFF // bit 15 is the sign bit // bits 14..11 are the exponent // bits 10..0 are the the mantissa. Unlike IEEE format, // the msb is transmitted; this means that numbers // might not be normalized, but makes coding for // underflow easier. // As with IEEE format, negative zero is possible, so // we special-case that in hopes that JavaScript will // also cooperate. // // The result is a number in the open interval (-1.0, 1.0); // // throw away high bits for repeatability. rawSflt16 &= 0xFFFF; // special case minus zero: if (rawSflt16 == 0x8000) return -0.0; // extract the sign. var sSign = ((rawSflt16 & 0x8000) !== 0) ? -1 : 1; // extract the exponent var exp1 = (rawSflt16 >> 11) & 0xF; // extract the "mantissa" (the fractional part) var mant1 = (rawSflt16 & 0x7FF) / 2048.0; // convert back to a floating point number. We hope // that Math.pow(2, k) is handled efficiently by // the JS interpreter! If this is time critical code, // you can replace by a suitable shift and divide. var f_unscaled = sSign * mant1 * Math.pow(2, exp1 - 15); return f_unscaled; } ``` ## Grafana Dashboard see `frontend/` ![screenshot of grafana-dashboard](doc/screenshot_dashboard.png)