From 3c53f94c1ba20e495f578ea42d776dedb1acb54e Mon Sep 17 00:00:00 2001
From: Terra <terra@clerie.de>
Date: Sun, 24 Apr 2022 22:06:06 +0200
Subject: [PATCH] Added RTC offset calculation to return absolute time

---
 MultiNode/Configurator.py |  4 ++--
 MultiNode/MNLib.cpp       | 12 ++++++++----
 MultiNode/MultiNode.ino   |  7 +++----
 RasPi/MultiNode.py        | 23 +++++++++++++----------
 TODO                      |  3 +--
 5 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/MultiNode/Configurator.py b/MultiNode/Configurator.py
index 47412e2..954bac2 100644
--- a/MultiNode/Configurator.py
+++ b/MultiNode/Configurator.py
@@ -31,7 +31,7 @@ jitter = int.from_bytes(config[17:21], byteorder="little")
 pointers = list(config[21 : 21 + n_devices])
 
 modem_frequency = 868.0
-modem_power = 0
+modem_power = 2
 client_address = 0x1234
 server_address = 0x0001
 
@@ -90,4 +90,4 @@ client_key = 0x0#0x7ed64cce5b5d8e85
 port.write(b"k")
 port.write(struct.pack("<QQ", client_key, server_key))
 
-#port.write(b"s")
\ No newline at end of file
+port.write(b"s")
\ No newline at end of file
diff --git a/MultiNode/MNLib.cpp b/MultiNode/MNLib.cpp
index eb79d64..2db0ebf 100644
--- a/MultiNode/MNLib.cpp
+++ b/MultiNode/MNLib.cpp
@@ -13,13 +13,11 @@ bool _is_client;
 uint8_t configuration_memory[CFGMEM];
 DeviceBase* devices[N_DEVICES];
 uint32_t last_server_message_id = 0;
+uint32_t rtc_offset = 0;
 
 //void init_mn(bool is_client = true)
 void initMN()
 {
-  if (batteryVoltage() < 3.5 && !USBDevice.connected()) // Shut off below this voltage, down to 3.1 V should be OK if the regulator has a dropout of 400 mV and conducts fully if its output is below 3.3 V
-    LowPower.deepSleep();
-    
   //_is_client = is_client;
 
   EEPROM.setCommitASAP(false); // Don't unnecessarily write to the EEPROM
@@ -95,6 +93,9 @@ void initMN()
 
   initializeDevices();
   initRTC();
+
+  if (batteryVoltage() < 3.5 && !USBDevice.connected()) // Shut off below this voltage, down to 3.1 V should be OK if the regulator has a dropout of 400 mV and conducts fully if its output is below 3.3 V
+    LowPower.deepSleep();
 }
 
 void test()
@@ -306,8 +307,11 @@ bool receive()
         switch (message_type)
         {
           case MT_Time:
+            rtc_offset = server_message_id - RTC->MODE1.COUNT.reg;
+          
             if (server_message_id > message_id) // Ensure that IDs are sequential
               message_id = server_message_id;
+
             return true;
             break;
         }
@@ -444,5 +448,5 @@ void initRTC() // https://github.com/arduino-libraries/RTCZero/blob/master/src/R
 
 uint32_t getRTC()
 {
-  return RTC->MODE1.COUNT.reg;
+  return RTC->MODE1.COUNT.reg + rtc_offset;
 }
diff --git a/MultiNode/MultiNode.ino b/MultiNode/MultiNode.ino
index 1cc92a1..2fa2e7d 100644
--- a/MultiNode/MultiNode.ino
+++ b/MultiNode/MultiNode.ino
@@ -75,8 +75,8 @@ void loop()
         SerialUSB.print("Battery voltage: ");
         SerialUSB.println(batteryVoltage());
 
-        SerialUSB.print("RTC time: ");
-        SerialUSB.println(RTC->MODE1.COUNT.reg);
+        SerialUSB.print("RTC + offset time: ");
+        SerialUSB.println(getRTC());
         SerialUSB.println("END");
         break;
 
@@ -155,7 +155,7 @@ void loop()
   long next_tick_sensors_dt = next_tick_sensors - now_time;
   long min_delay = min(next_tick_device_dt, next_tick_sensors_dt);
   
-  if (min_delay > 1000 && !USBDevice.connected())
+  if (min_delay > 1000 && !USBDevice.connected() && message_id > 1000000000) // Listen until the time is initialized
   {
     power_sleep(min_delay);
     offset += min_delay;
@@ -170,5 +170,4 @@ void power_sleep(uint32_t milliseconds)
   setLoopPower(OFF);
   LowPower.sleep(milliseconds);
   radio.setModeIdle();
-  delay(100);
 }
diff --git a/RasPi/MultiNode.py b/RasPi/MultiNode.py
index e76c05d..af256b3 100644
--- a/RasPi/MultiNode.py
+++ b/RasPi/MultiNode.py
@@ -90,14 +90,15 @@ class MultiNode:
 			print(f"Hash doesn't match! Expected {hash_function.digest()} got {data_hash}")
 			return
 
-		if not rx_id in self.devices:
-			self.devices[rx_id] = {"last_message_id": msg_id}
-
-		self.decode_packet(self.devices[rx_id], data)
-		self.print_data()
-
-		# print(f"{tx_id} #{msg_id}: {decode_packet(data):.3f} V, {payload.rssi} dB(?) RSSI, {payload.snr} dB(?) SNR {(time.clock_gettime_ns(0)) / 1e9}")
+		if not tx_id in self.devices:
+			self.devices[tx_id] = {}
+		
+		self.devices[tx_id]["last_message_id"] = msg_id
+		self.decode_packet(self.devices[tx_id], data)
+		# RSSI cahnges from -13 to -27 on change from +20 to +2 dBm TX setting
+		# print(f"{tx_id} #{msg_id}: {self.decode_packet(self.devices[rx_id], data)} V, {payload.rssi} dB(?) RSSI, {payload.snr} dB(?) SNR {(time.clock_gettime_ns(0)) / 1e9}")
 		# print(f"{tx_id} #{msg_id}: {data.hex()} {self.decode_packet(data)}, {payload.rssi} dB(?) RSSI, {payload.snr} dB(?) SNR {(time.clock_gettime_ns(0)) / 1e9}")
+		self.print_data()
 
 	def send_packet(self, target: int, data):
 		assert len(data) < 256
@@ -121,17 +122,19 @@ class MultiNode:
 	def print_data(self):
 		for device_id in self.devices:
 			device = self.devices[device_id]
-			print(f'{device_id}:')
+			print(f'Node {device_id} @ ID {device["last_message_id"]}:')
 
 			if "status" in device:
-				print(f'\t{device["status"]["battery"]} V {device["status"]["temperature"]} °C')
+				print(f'\t{device["status"]["battery"]:.3f} V {device["status"]["temperature"]:.1f} °C')
 
 			if "sensors" in device:
 				for sensor in device["sensors"]:
 					if sensor["value"] == math.nan:
 						print(f'\tCH {sensor["channel"]} on Pin {sensor["pin"]}: ERROR')
 					else:
-						print(f'\tCH {sensor["channel"]} on Pin {sensor["pin"]}: {sensor["value"]} {self.sensor_type_table[sensor["type"]]}')
+						print(f'\tCH {sensor["channel"]} on Pin {sensor["pin"]}: {sensor["value"]:.4f} {self.sensor_type_table[sensor["type"]]}')
+			
+			print()
 
 
 if __name__ == "__main__":
diff --git a/TODO b/TODO
index 7fb50c9..4707e75 100644
--- a/TODO
+++ b/TODO
@@ -1,5 +1,4 @@
 - Add password protection to configuration
 - Webserver
 - More sensor types
-- Control of node outputs
-- Power saving features
\ No newline at end of file
+- Control of node outputs
\ No newline at end of file