From bf7ed9538ba6bba4e83b075d2ca93df134a5242a Mon Sep 17 00:00:00 2001 From: Rene Reimann Date: Tue, 27 May 2025 17:45:19 +0200 Subject: [PATCH 1/2] added service and endpoint for arduino communication --- dripline/extensions/__init__.py | 2 + dripline/extensions/arduino_endpoint.py | 22 ++++++++ dripline/extensions/arduino_service.py | 73 +++++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 dripline/extensions/arduino_endpoint.py create mode 100644 dripline/extensions/arduino_service.py diff --git a/dripline/extensions/__init__.py b/dripline/extensions/__init__.py index b62df1e..2c69572 100644 --- a/dripline/extensions/__init__.py +++ b/dripline/extensions/__init__.py @@ -7,3 +7,5 @@ # Modules in this directory from .add_auth_spec import * +from .arduino_endpoint import * +from .arduino_service import * diff --git a/dripline/extensions/arduino_endpoint.py b/dripline/extensions/arduino_endpoint.py new file mode 100644 index 0000000..d836f87 --- /dev/null +++ b/dripline/extensions/arduino_endpoint.py @@ -0,0 +1,22 @@ +from dripline.core import Entity, calibrate, ThrowReply + +import logging +logger = logging.getLogger(__name__) + +__all__ = [] +__all__.append("ArduinoGetEntity") + +class ArduinoGetEntity(Entity): + def __init__(self, + get_str=None, + **kwargs): + + Entity.__init__(self, **kwargs) + self.get_str = get_str + + @calibrate() + def on_get(self): + return self.service.send_to_device([self.get_str]) + + def on_set(self, value): + raise ThrowReply('message_error_invalid_method', f"endpoint '{self.name}' does not support set") \ No newline at end of file diff --git a/dripline/extensions/arduino_service.py b/dripline/extensions/arduino_service.py new file mode 100644 index 0000000..0be758e --- /dev/null +++ b/dripline/extensions/arduino_service.py @@ -0,0 +1,73 @@ +import re +import socket +import threading + +from dripline.core import Service + +import logging +logger = logging.getLogger(__name__) + +__all__ = [] +__all__.append('EthernetArduinoService') + +class EthernetArduinoService(Service): + def __init__(self, + socket_info, + socket_timeout=10, + **kwargs + ): + + Service.__init__(self, **kwargs) + + if isinstance(socket_info, str): + logger.debug(f"Formatting socket_info: {socket_info}") + re_str = "\([\"'](\S+)[\"'], ?(\d+)\)" + (ip,port) = re.findall(re_str,socket_info)[0] + socket_info = (ip,int(port)) + + self.alock = threading.Lock() + self.socket = socket.socket() + + self.socket_timeout = float(socket_timeout) + self.socket_info = socket_info + + + def send_to_device(self, commands, **kwargs): + + if isinstance(commands, str): + commands = [commands] + + self.alock.acquire() + data = [] + try: + data = self._send_commands(commands) + except Exception as err: + logger.critical(str(err)) + finally: + self.alock.release() + to_return = ';'.join(data) + logger.debug(f"should return:\n{to_return}") + return to_return + + + def _send_commands(self, commands): + all_data=[] + + for command in commands: + try: + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.settimeout(self.socket_timeout) + self.socket.connect(self.socket_info) + self.socket.sendall(bytes(command, encoding="utf-8")) + data = self.socket.recv(1024) + data = data.rstrip(b'\x00\n').decode("utf-8") + except Exception as err: + logger.warning(f"While socket communication we received an error: {err}") + finally: + self.socket.close() + + logger.info(f"Received: {data}") + + all_data.append(data) + + return all_data \ No newline at end of file From 316dd1cade28ec0f69f2938bf3d2842f411daf0a Mon Sep 17 00:00:00 2001 From: Rene Reimann Date: Tue, 10 Jun 2025 14:52:15 +0200 Subject: [PATCH 2/2] adding sketch that is running on the arduino and provides the other side of the communication --- dragonfly/sketch_coolingloopsensor.ino | 154 +++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 dragonfly/sketch_coolingloopsensor.ino diff --git a/dragonfly/sketch_coolingloopsensor.ino b/dragonfly/sketch_coolingloopsensor.ino new file mode 100644 index 0000000..cc1392f --- /dev/null +++ b/dragonfly/sketch_coolingloopsensor.ino @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include + +/* ----------------------------- CONFIGURATION ----------------------------*/ + +#define DEBUG 1 // 0 disabled, 1 enabled +#define DHCP 1 // 0 disabled, 1 enabled +#define MAC 0 // 0 for astro-yacht, 1 for astro-zabra, 2 for astro-aye + +/* ------------------------------------------------------------------------*/ + +#if DEBUG +#define DEBUG_PRINTLN(x) Serial.println(x) +#define DEBUG_PRINT(x) Serial.print(x) +#define DEBUG_PRINTIP(x, y) ether.printIp(x, y) +#else +#define DEBUG_PRINTLN(x) +#define DEBUG_PRINT(x) +#define DEBUG_PRINTIP(x) +#endif + +const byte pinFlowmeter = 3; // Interrupt pin (D2) +const byte pinTemperature = 5; // Digital pin (D6) +const byte pinPressure = 6; + +volatile unsigned int pulseCount = 0; // Stores number of pulses +const int flowMeasurementDuration = 500; // Microsecond + +OneWire oneWire(pinTemperature); +DallasTemperature temperatureSensor(&oneWire); + +#if MAC == 0 +static byte mymac[] = {0x5a, 0x09, 0xb5, 0xaf, 0xd8, 0x11}; +#elif MAC == 1 +static byte mymac[] = {0x5a, 0x09, 0xb5, 0xaf, 0xd8, 0x10}; +#elif MAC == 2 +static byte mymac[] = {0x5a, 0x09, 0xb5, 0xaf, 0xd8, 0x09}; +#endif + +#if DHCP == 0 +static byte myip[] = {192, 168, 1, 10}; +// Gateway IP address +static byte gwip[] = {192, 168, 0, 10}; +#endif + +byte Ethernet::buffer[500]; // TCP/IP send and receive buffer + +void pulseISR() { + pulseCount++; // Interrupt service routine: Increment the pulse count on each interrupt +} + +float getTemperatureC() { + /* Returns temperature in degrees Celcius */ + temperatureSensor.requestTemperatures(); + return temperatureSensor.getTempCByIndex(0); +} + +float getPressureV() { + /* Returns the pressure in Volts */ + int sensorValue = analogRead(pinPressure); + return sensorValue * (5.0 / 1023.0); +} + +float getFlowHz() { + /* Returns pulse frequency in Herz */ + pulseCount = 0; + delay(flowMeasurementDuration); + float frequency = (float)pulseCount * 1000.0 / (flowMeasurementDuration); + return frequency; +} + +void setup() { +#if DEBUG + Serial.begin(115200); +#endif + + pinMode(pinFlowmeter, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(pinFlowmeter), pulseISR, RISING); + + temperatureSensor.begin(); + if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) { + DEBUG_PRINTLN("Failed to access Ethernet controller."); + } else { + DEBUG_PRINTLN("Ethernet controller sucessfully accessed."); + } + +#if DHCP == 0 + ether.staticSetup(myip, gwip); +#else + if (!ether.dhcpSetup()) { + DEBUG_PRINTLN("DHCP failed"); + } else { + DEBUG_PRINTIP("DHCP request successful. IP-Adress: ", ether.myip); + DEBUG_PRINT("Lease time: "); + DEBUG_PRINTLN(ether.getLeaseTime()); + } +#endif +} + +void loop() { + word len = ether.packetReceive(); + word pos = ether.packetLoop(len); + + if (pos) { + char *data = (char *)Ethernet::buffer + pos; + DEBUG_PRINT("Received data: "); + DEBUG_PRINTLN(data); + + float sensorData = 0; + boolean caseFound = false; + + char response[10]; + memset(response, '\n', sizeof(response)); + if (strncmp(data, "temp?", 5) == 0) { + sensorData = getTemperatureC(); + dtostrf(sensorData, 4, 4, response); + } else if (strncmp(data, "pres?", 5) == 0) { + sensorData = getPressureV(); + dtostrf(sensorData, 4, 4, response); + } else if (strncmp(data, "flow?", 5) == 0) { + sensorData = getFlowHz(); + dtostrf(sensorData, 4, 4, response); + } else if (strncmp(data, "test?", 5) == 0) { + strcpy(response, "success"); + } else { + strcpy(response, "invalid"); + } + + DEBUG_PRINT("Sending data: "); + DEBUG_PRINTLN(response); + + memcpy(ether.tcpOffset(), response, sizeof(response)); + ether.httpServerReply(sizeof(response) - 1); + } + + // if DHCP lease is expired or millis wrap over after 49 days +#if DHCP + float leaseStart = ether.getLeaseStart(); + if ((millis() - leaseStart >= ether.getLeaseTime()) || + (millis() < leaseStart)) { + if (!ether.dhcpSetup()) { + DEBUG_PRINTLN("DHCP renew failed"); + delay(60000); // wait for one minute before retrying. + } else { + DEBUG_PRINTIP("DHCP renewed. IP-Adress: ", ether.myip); + DEBUG_PRINT("Lease time: "); + DEBUG_PRINTLN(ether.getLeaseTime()); + } + } +#endif +}