Skip to content

Arduino Service and Endpoint #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions dragonfly/sketch_coolingloopsensor.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#include <DallasTemperature.h>
#include <EtherCard.h>
#include <IPAddress.h>
#include <OneWire.h>
#include <string.h>

/* ----------------------------- 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
}
2 changes: 2 additions & 0 deletions dripline/extensions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
# Modules in this directory

from .add_auth_spec import *
from .arduino_endpoint import *
from .arduino_service import *
from .thermo_fisher_endpoint import *
from .ethernet_thermo_fisher_service import *
22 changes: 22 additions & 0 deletions dripline/extensions/arduino_endpoint.py
Original file line number Diff line number Diff line change
@@ -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")
73 changes: 73 additions & 0 deletions dripline/extensions/arduino_service.py
Original file line number Diff line number Diff line change
@@ -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