From c63bd9d2d77d8e2ebe950ac84a6aebb061d3c647 Mon Sep 17 00:00:00 2001 From: Terra Date: Sun, 24 Apr 2022 14:54:40 +0200 Subject: [PATCH] Add time sync --- .style.yapf | 4 + MultiNode/Configurator.py | 20 ++++- MultiNode/MNLib.cpp | 63 +++++++++++-- MultiNode/MNLib.h | 14 ++- MultiNode/MultiNode.ino | 41 +++++---- RasPi/Config.toml | 1 + RasPi/MultiNode.py | 183 ++++++++++++++++++++++++++------------ RasPi/RXTest.py | 43 +-------- TODO | 2 - 9 files changed, 243 insertions(+), 128 deletions(-) create mode 100644 .style.yapf diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 0000000..215bd83 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,4 @@ +[style] +based_on_style=pep8 +use_tabs=True +column_limit=200 \ No newline at end of file diff --git a/MultiNode/Configurator.py b/MultiNode/Configurator.py index 390780e..7480d43 100644 --- a/MultiNode/Configurator.py +++ b/MultiNode/Configurator.py @@ -24,13 +24,22 @@ modem_power = config[4] client_address = int.from_bytes(config[5:7], byteorder="little") server_address = int.from_bytes(config[7:9], byteorder="little") -pointers = list(config[9 : 9 + n_devices]) + +sensor_update_interval = int.from_bytes(config[9:13], byteorder="little") +device_update_interval = int.from_bytes(config[13:17], byteorder="little") +jitter = int.from_bytes(config[17:21], byteorder="little") +pointers = list(config[21 : 21 + n_devices]) modem_frequency = 868.0 modem_power = 0 client_address = 0x1234 server_address = 0x0001 +# In ms +sensor_update_interval = 3000 +device_update_interval = 7000 +jitter = 1000 + def pack_device(): data = struct.pack("> 8 & 0xFF)) + { + + hash_generator.reset(&configuration.server_secret_key, sizeof(configuration.server_secret_key), HASH_LENGTH); + hash_generator.update(buffer, len - HASH_LENGTH); + uint8_t hash[HASH_LENGTH]; + hash_generator.finalize(hash, HASH_LENGTH); + for (size_t i = 0; i < HASH_LENGTH; i++) + if (buffer[len - HASH_LENGTH + i] != hash[i]) + return false; + + uint32_t server_message_id = buffer[4] | ((uint32_t)buffer[5] << 8) | ((uint32_t)buffer[6] << 16) | ((uint32_t)buffer[7] << 24); + if (server_message_id > last_server_message_id) + { + uint8_t packet_length = buffer[8]; + MessageType message_type = (MessageType)buffer[9]; + + switch (message_type) + { + case MT_Time: + if (server_message_id > message_id) // Ensure that IDs are sequential + message_id = server_message_id; + return true; + break; + } + } + } + } + return false; +} + void initializeDevices() { for (int i = 0; i < N_DEVICES; i++) @@ -297,12 +339,12 @@ DeviceBase* getDevice(uint8_t pointer) return new Device; } -void loopSensors() +void loopMN() { + receive(); + for (int i = 0; i < N_DEVICES; i++) - { devices[i]->loop(); - } } void sendSensorData() @@ -331,3 +373,14 @@ void sendSensorData() memcpy(&data[3], &buffer, cnt * (sizeof(float) + sizeof(uint8_t) * 2)); send(data, sizeof(uint8_t) + sizeof(uint16_t) + cnt * (sizeof(float) + sizeof(uint8_t) * 2)); } + +void sendDeviceData() +{ + float temperature = temperature_sensor.readInternalTemperature(); + float voltage = batteryVoltage(); + uint8_t data[9]; + data[0] = MT_DeviceStatus; + memcpy(&data[1], &voltage, 4); + memcpy(&data[5], &temperature, 4); + send(data, 9); +} diff --git a/MultiNode/MNLib.h b/MultiNode/MNLib.h index f3e578f..d7782b3 100644 --- a/MultiNode/MNLib.h +++ b/MultiNode/MNLib.h @@ -42,6 +42,7 @@ #define N_DEVICES 15 #define CFGMEM 256 +#define BROADCAST 0xFFFF #define ERROR_BLINK_HALF_INTERVAL 100 // 5 Hz @@ -56,12 +57,16 @@ struct MNConfiguration uint16_t client_address; uint16_t server_address; + uint32_t sensor_update_interval; + uint32_t device_update_interval; + uint32_t jitter; + uint8_t devices[N_DEVICES]; uint64_t client_secret_key; uint64_t server_secret_key; } __attribute__ ((packed)); -static_assert(sizeof(MNConfiguration) == 40, "MNConfiguration has the wrong size! Please edit this in the configurator too"); +static_assert(sizeof(MNConfiguration) == 52, "MNConfiguration has the wrong size! Please edit this in the configurator too"); struct DeviceBase { @@ -143,6 +148,7 @@ enum MessageType { MT_DeviceStatus = 1, MT_SensorStatus = 2, + MT_Time = 2, }; @@ -156,7 +162,7 @@ extern DeviceBase* devices[N_DEVICES]; //void init_mn(bool is_client); -void init_mn(); +void initMN(); void test(); void printStatusReport(); void setLoopPower(bool state); @@ -166,8 +172,10 @@ void refreshConfig(); float batteryVoltage(); void errorBlink(int n); // Quickly blink n times bool send(uint8_t data[], uint8_t len); +bool receive(); void initializeDevices(); DeviceBase* getDevice(uint8_t pointer); -void loopSensors(); +void loopMN(); void sendSensorData(); +void sendDeviceData(); #endif diff --git a/MultiNode/MultiNode.ino b/MultiNode/MultiNode.ino index 00516ce..be32348 100644 --- a/MultiNode/MultiNode.ino +++ b/MultiNode/MultiNode.ino @@ -6,10 +6,10 @@ //#define IS_SERVER -byte LoopState = 0; -char inByte; -unsigned long nextTick = 0; -unsigned int msTick = 2000; +unsigned long tick_tracker_sensors = 0; +unsigned long tick_tracker_device = 0; +unsigned long next_tick_sensors = 0; +unsigned long next_tick_device = 0; @@ -17,7 +17,6 @@ unsigned int msTick = 2000; //RHReliableDatagram rfManager(rfm95, CLIENT_ADDRESS); // Internal on-chip Temperature sensor -TemperatureZero TempZero = TemperatureZero(); void setup() @@ -29,14 +28,15 @@ void setup() delay(1000); SerialUSB.println("owo"); }*/ - init_mn(); + initMN(); /*for (int i = 0; i < 2; i++) { delay(1000); SerialUSB.println("awa"); } printStatusReport();*/ - nextTick = millis(); + tick_tracker_sensors = millis(); + tick_tracker_device = millis(); } @@ -111,6 +111,8 @@ void loop() case 'w': SerialUSB.readBytes(reinterpret_cast(&configuration), config_size); refreshConfig(); + tick_tracker_sensors = millis(); + tick_tracker_device = millis(); break; case 'R': // Read configuration memory (extended configuration for each sensor) @@ -135,20 +137,23 @@ void loop() } } - loopSensors(); + loopMN(); - // TICK-ROUTINE - if (millis() > nextTick) + if (millis() >= next_tick_sensors) { sendSensorData(); - - SerialUSB.println("s"); - uint8_t data[5]; - data[0] = MT_DeviceStatus; - float bv = batteryVoltage(); - memcpy(&data[1], &bv, 4); - send(data, 5); - nextTick = nextTick + msTick; + tick_tracker_sensors = tick_tracker_sensors + configuration.sensor_update_interval; + next_tick_sensors = tick_tracker_sensors + random(configuration.jitter); + digitalWrite(LED_BUILTIN, HIGH); + delay(2); + digitalWrite(LED_BUILTIN, LOW); + } + + if (millis() >= next_tick_device) + { + sendDeviceData(); + tick_tracker_device = tick_tracker_device + configuration.device_update_interval; + next_tick_device = tick_tracker_device + random(configuration.jitter); digitalWrite(LED_BUILTIN, HIGH); delay(2); digitalWrite(LED_BUILTIN, LOW); diff --git a/RasPi/Config.toml b/RasPi/Config.toml index f7aead3..c8884b3 100644 --- a/RasPi/Config.toml +++ b/RasPi/Config.toml @@ -1,6 +1,7 @@ [server] address = 0x0001 secret_key = 0x2e29b257521dc792 +time_interval = 5 [node] address = 0x1FFF diff --git a/RasPi/MultiNode.py b/RasPi/MultiNode.py index 53f2523..17d8c99 100644 --- a/RasPi/MultiNode.py +++ b/RasPi/MultiNode.py @@ -1,71 +1,140 @@ from enum import IntEnum -import struct from pyblake2 import blake2s -import time -import toml +from pyLoraRFM9x import LoRa, ModemConfig +import time, toml, math, struct HASH_LENGTH = 8 -with open("Config.toml", "r") as config_file: - config = toml.loads(config_file.read()) - -print(config) -devices = {} - class MessageType(IntEnum): - DeviceStatus = 1 - SensorStatus = 2 + DeviceStatus = 1 + SensorStatus = 2 + Time = 2 -def decode_packet(data): - packet_type = data[0] +class MultiNode: + sensor_type_table = {1: "V", 2: "mA"} - # match packet_type: - # case MessageType.DeviceStatus: + def __init__(self): + with open("Config.toml", "r") as config_file: + config = toml.loads(config_file.read()) - if packet_type == MessageType.DeviceStatus: - return {"Battery voltage": struct.unpack('> i) & 1: - channels.append(i) - - sensor_data = [] - for i in range(len(channels)): - offset = i * 6 - sensor_data.append({ - "channel": channels[i], - "type": data[3 + offset], - "pin": data[4 + offset], - "value": struct.unpack(' self.time_interval: + self.send_packet(0xFFFF, int(MessageType.Time).to_bytes(1, "little")) + self.last_time_message += self.time_interval + #print("Sent time") + + def decode_packet(self, device, data): + packet_type = data[0] + + # match packet_type: + # case MessageType.DeviceStatus: + + if packet_type == MessageType.DeviceStatus: + device["status"] = {"battery": struct.unpack('> i) & 1: + channels.append(i) + + sensor_data = [] + for i in range(len(channels)): + offset = i * 6 + sensor_data.append({"channel": channels[i], "type": data[3 + offset], "pin": data[4 + offset], "value": struct.unpack('