Initial project: XIAO ESP32S3 + SX1262 LoRa sensor link hytte–hjem

- cabin_node: subscribes to local MQTT (ESPHome sensors), sends
  temperature, battery voltage/SOC and switch states over LoRa SF12
- cabin_gw: receives LoRa packets, publishes JSON to home MQTT broker
- Bidirectional: gateway forwards ON/OFF commands from home HA to node
- cabin_node always in RX mode (12V powered) — commands arrive instantly
- ESPHome config for ESP32 on teknisk rom: Victron MPPT BLE + JBD BMS
  BLE + DS18B20 temperatures + GPIO switches for varme/VVB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 23:11:35 +01:00
commit a544594769
11 changed files with 756 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
#pragma once
// LoRa radio parameters — must match exactly on node and gateway
#define LORA_FREQ 868.0 // MHz
#define LORA_SF 12
#define LORA_BW 125.0 // kHz
#define LORA_CR 5
#define LORA_SYNC_WORD 0xAB // distinct from ice-track (0x34)
#define LORA_POWER 22 // dBm (SX1262 max)
// Wio-SX1262 pins for XIAO ESP32S3
// Verify against https://wiki.seeedstudio.com/wio_sx1262_with_xiao_esp32s3
#define LORA_NSS 44 // D7
#define LORA_RST 43 // D6
#define LORA_DIO1 2 // D1
#define LORA_BUSY 1 // D0
// Send interval (node) — 30 min fills one packet; adjust 14x/hour
#define SEND_INTERVAL_MS (30UL * 60UL * 1000UL)
// MQTT broker (home, shared with mitt_lora)
#define MQTT_HOST "192.168.86.31"
#define MQTT_PORT 1883
#define MQTT_USER "mqtt"
#ifndef MQTT_PASS
#define MQTT_PASS ""
#endif
// MQTT topics (cabin ESPHome → node subscribes to these)
#define TOPIC_TEMP_IN "hytte/sensor/temp_inne"
#define TOPIC_TEMP_OUT "hytte/sensor/temp_ute"
#define TOPIC_BATT_MV "hytte/sensor/batt_mv"
#define TOPIC_BATT_PCT "hytte/sensor/batt_pct"
// MQTT topic gateway publishes received packets to (home broker)
#define TOPIC_GW_STATUS "hytte/lora/status"
// Command topics (home HA publishes → cabin_gw → LoRa → cabin_node → ESPHome)
// Payload: "ON" or "OFF"
#define TOPIC_CMD_VARME "hytte/cmd/varme"
#define TOPIC_CMD_VVB "hytte/cmd/vvb"
// ESPHome publishes switch states here (cabin_node subscribes)
#define TOPIC_STATE_VARME "hytte/switch/varme/state"
#define TOPIC_STATE_VVB "hytte/switch/vvb/state"
// WiFi credentials
#ifndef WIFI_SSID
#define WIFI_SSID "your-ssid"
#endif
#ifndef WIFI_PASS
#define WIFI_PASS "your-pass"
#endif
// HMAC key — 32+ chars, keep secret
#ifndef HMAC_KEY
#define HMAC_KEY "hytte-link-hmac-key-replace-me"
#endif
#if __has_include("secrets.h")
#include "secrets.h"
#endif
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "mbedtls/md.h"
#include "config.h"
// Returns a 4-byte truncated HMAC-SHA256 over `data` of `len` bytes.
inline uint32_t hmac_sig(const uint8_t *data, size_t len)
{
static const char *key = HMAC_KEY;
uint8_t out[32];
mbedtls_md_hmac(
mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
reinterpret_cast<const uint8_t *>(key), strlen(key),
data, len, out);
uint32_t sig;
memcpy(&sig, out, 4);
return sig;
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <stdint.h>
#define CABIN_PACKET_MAGIC 0xCA
#define CABIN_CMD_MAGIC 0xCB
// Command IDs
#define CMD_VARME 0x01
#define CMD_VVB 0x02 // varmtvannsbereder
// Wire format: 13 bytes total
// At SF12 BW125: ~1.3s airtime
// flags bits: 0=varme, 1=vvb (1=on, 0=off)
#define CABIN_FLAG_VARME (1 << 0)
#define CABIN_FLAG_VVB (1 << 1)
struct __attribute__((packed)) CabinPacket {
uint8_t magic; // = CABIN_PACKET_MAGIC
uint8_t seq; // rolling counter
int16_t temp_in_x10; // indoor temp * 10 (213 = 21.3 °C), INT16_MIN = no data
int16_t temp_out_x10; // outdoor temp * 10, INT16_MIN = no data
uint16_t batt_mv; // battery voltage mV (12V system: ~1000014400)
uint8_t batt_pct; // SOC 0100, 0xFF = no data
uint8_t flags; // switch states: bit0=varme, bit1=vvb
uint32_t sig; // truncated HMAC-SHA256
};
// Command packet: home → gateway → node → ESPHome switch
// 8 bytes total
struct __attribute__((packed)) CabinCmdPacket {
uint8_t magic; // = CABIN_CMD_MAGIC
uint8_t seq;
uint8_t cmd_id; // CMD_VARME, CMD_VVB, ...
uint8_t value; // 0 = off, 1 = on
uint32_t sig;
};
+7
View File
@@ -0,0 +1,7 @@
#pragma once
// Copy to secrets.h and fill in before building
#define WIFI_SSID "your-wifi-ssid"
#define WIFI_PASS "your-wifi-password"
#define MQTT_PASS "your-mqtt-password"
#define HMAC_KEY "your-secret-hmac-key-at-least-32-chars"