muizenval

Observe mouse traps remotely
Log | Files | Refs

commit d555132119962605dbb47e692725ba10632e57d2
parent 208f81550eca2319f5f70c7ac61f83a579cb73e7
Author: Friedel Schön <[email protected]>
Date:   Tue, 21 Jun 2022 11:08:23 +0200

adding support to string request

Diffstat:
M.vscode/arduino.json | 2+-
M5g-client/5g-client.ino | 138++++++++++++++------------------------------------------------------------------
A5g-client/http.ino | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M5g-client/include/config.h | 11+++++++----
A5g-client/include/http.h | 29+++++++++++++++++++++++++++++
A5g-client/include/led.h | 27+++++++++++++++++++++++++++
A5g-client/led.ino | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Aold_client.ino | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mremote.py | 52++++++++++++----------------------------------------
Mtest-server.py | 19+++++++++----------
10 files changed, 415 insertions(+), 170 deletions(-)

diff --git a/.vscode/arduino.json b/.vscode/arduino.json @@ -1,6 +1,6 @@ { "sketch": "5g-client/5g-client.ino", "board": "SODAQ:samd:sodaq_sara", - "port": "/dev/tty.usbmodem1D11101", + "port": "/dev/tty.usbmodem142301", "output": "build" } \ No newline at end of file diff --git a/5g-client/5g-client.ino b/5g-client/5g-client.ino @@ -1,6 +1,6 @@ #include "include/config.h" -#include "include/modem.h" -#include "include/remote.h" +#include "include/http.h" +#include "include/led.h" #include <Sodaq_LSM303AGR.h> #include <Sodaq_UBlox_GPS.h> @@ -11,27 +11,20 @@ #define BATVOLT_R2 10.0f #define BATVOLT_PIN BAT_VOLT -#define statusDelay 0.5 // seconds +#define statusDelay 1.0 // seconds #define batteryFactor (0.978 * (BATVOLT_R1 / BATVOLT_R2 + 1) / ADC_AREF) -sara_modem modem; +http_client http; Sodaq_LSM303AGR accel; -serial_remote remote; void setup() { - // -*- hardware initiation -*- - - usbSerial.begin(remoteBaud); - while (usbWait && !usbSerial) - ; + led.begin(); + http.begin(); pinMode(BATVOLT_PIN, INPUT); pinMode(CHARGER_STATUS, INPUT); - // modem.init(); - remote.begin(); - Wire.begin(); delay(1000); sodaq_gps.init(GPS_ENABLE); @@ -41,87 +34,10 @@ void setup() { // Enable the Accelerometer accel.enableAccelerometer(); - - remote.connect("127.0.0.1", 5000); - - // modem.send("ATE0"); // disable command-echo - - // if (modem.send("AT+CPIN=\"" SIM_PIN "\"") == sara_modem::COMMAND_ERROR) { - // // usbSerial.println("[EROR] sim can't be unlocked, wrong PIN"); - // return; - // } - // usbSerial.println(prefixInfo "sim successful unlocked"); - /* - - modem.send("AT+CPSMS=0"); // Disable Power Saving Mode - modem.send("AT+CEDRXS=0"); // Disable eDRX - // usbSerial.println(prefixInfo "disabled power safe"); - - - // -*- internet initialization -*- - char info[100]; - - modem.send("AT+CFUN=15", sara_modem::COMMAND_BLOCK); // Reset the module - modem.send("AT+UMNOPROF=1", sara_modem::COMMAND_BLOCK); // Set MNO profile (1=automatic,100=standard europe) - modem.send("AT+URAT?", info); - // usbSerial.print(prefixInfo "urat: "); - // usbSerial.println(info); - modem.send("AT+URAT=8", sara_modem::COMMAND_IGNORE); // Set URAT to LTE-M/NB-IOT - modem.send("AT+CEREG=3", sara_modem::COMMAND_IGNORE); // Enable URCs - modem.send("AT+CGDCONT=1,\"IP\",\"" simAPN "\"", sara_modem::COMMAND_BLOCK); // Set the APN - modem.send("AT+CFUN=1"); // enable radio - modem.send("AT+COPS=0,2", sara_modem::COMMAND_BLOCK); // Autoselect the operator - - // usbSerial.print(prefixInfo "waiting for connection"); - - char response[100]; - - // Check Siganl strenght, repeat till you have a valid CSQ (99,99 means no signal) - while (modem.send("AT+CSQ", response, sara_modem::COMMAND_SILENT) == sara_modem::COMMAND_OK && !strcmp(response, "+CSQ: 99,99")) { - delay(1000); - // usbSerial.print("."); - } - - // Wait for attach, 1 = attached - while (modem.send("AT+CGATT?", response, sara_modem::COMMAND_SILENT) == sara_modem::COMMAND_OK && strcmp(response, "+CGATT: 1")) { - delay(1000); - // usbSerial.print("."); - } - // usbSerial.println(); - - // usbSerial.println(prefixInfo "connected!"); - - // -*- server connection -*- - - - //AT+UHTTP=0,0,"86.92.67.21" - //AT+UHTTP=0,5,80 - //AT+UHTTPC=0,5,"/api/search_connect","","TEST!",1 - - modem.send("AT+UHTTP=0,0,\"86.92.67.21\""); - modem.send("AT+UHTTP=0,5,80"); - modem.send("AT+UHTTPC=0,5,\"/api/search_connect\",\"\",\"TEST!\",1");*/ - - - // usbSerial.println(prefixInfo "initiation completed, starting remote:"); } - void loop() { - /* // -*- remote for custom commands -*- - while (usbSerial.available()) - modemSerial.write(usbSerial.read()); - - while (modemSerial.available()) - usbSerial.write(modemSerial.read()); - - char buffer[512]; - gps.read(buffer); - - if (buffer[0] != '\0') { - // usbSerial.print("gps | "); - // usbSerial.println(buffer); - }*/ + led.blink(); static int last = 0; int now = millis(); @@ -129,38 +45,30 @@ void loop() { static double lat = 0, lon = 0, accuracy = 0; if (now - last > statusDelay * 1000) { - if (sodaq_gps.scan(true, 10000)) { + if (sodaq_gps.scan(true, gpsTimeout * 1000)) { + led.set(status_led::COLOR_GREEN); + lat = sodaq_gps.getLat(); lon = sodaq_gps.getLon(); accuracy = 1.0 / sodaq_gps.getHDOP() * 100; // -> 100% the best, 0% the worst - // usbSerial.print(sodaq_gps.getLat(), 13); - // usbSerial.print(" - "); - // usbSerial.print(sodaq_gps.getLon(), 13); - // usbSerial.print(" ~ accuracy "); - // usbSerial.print(1.0 / sodaq_gps.getHDOP() * 100, 1); - // usbSerial.println("%"); + } else { + led.set(status_led::COLOR_BLUE); } - serial_remote::http_packet req, res; - req.method = "POST"; - req.endpoint = "/api/update"; - req.body["charging"] = (bool) digitalRead(CHARGER_STATUS); - req.body["latitude"] = lat; - req.body["longitude"] = lon; - req.body["accuracy"] = accuracy; - req.body["battery"] = batteryVoltage(); - req.body["temperature"] = temperature(); - - remote.send(req); + json req; + // req.method = "POST"; + // req.endpoint = "/api/update"; + req["latitude"] = lat; + req["longitude"] = lon; + req["accuracy"] = accuracy; + req["battery"] = batteryVoltage(); + req["temperature"] = temperature(); + req["charging"] = (bool) digitalRead(CHARGER_STATUS); + + http.send(http_client::HTTP_POST, "/api/update", req); last = now; } - - // usbSerial.print(batteryVoltage()); - // usbSerial.println("V battery"); - - // usbSerial.print(temperature()); - // usbSerial.println(" deg celsius"); } int temperature() { diff --git a/5g-client/http.ino b/5g-client/http.ino @@ -0,0 +1,79 @@ +#include "include/config.h" +#include "include/http.h" +#include "include/led.h" + +json null_response; + +void http_client::begin() { + led.set(status_led::COLOR_NONE, status_led::COLOR_CYAN); + + if (remoteForce) { + fallback(); + return; + } +} + +void http_client::fallback() { + led.set(status_led::COLOR_RED, status_led::COLOR_YELLOW); + remote = true; + + usbSerial.begin(remoteBaud); + while (!usbSerial) + led.blink(); + + led.set(status_led::COLOR_YELLOW); +} + +int http_client::send(http_client::method method, const char* endpoint, json body, json& response) { + static char buffer[512]; + json::stringify(body).toCharArray(buffer, 512); + return send(method, endpoint, buffer, response); +} + +int http_client::send(http_client::method method, const char* endpoint, const char* body, json& response) { + int code; + if (!remote) { + + } else { + switch (method) { + case http_client::HTTP_GET: + usbSerial.print("GET "); + break; + case http_client::HTTP_POST: + usbSerial.print("POST "); + } + usbSerial.print(endpoint); + usbSerial.print(" "); + usbSerial.println(body); + // body.printTo(usbSerial); + usbSerial.println(); + + char buffer[256]; + int i = 0; + int state = 0; // 0 = status-code; 1 = json + char c; + + for (;;) { + if (usbSerial.available()) { + c = usbSerial.read(); + if (c == '\r') { + // do nothing + } else if (state == 0 && c == ' ') { + buffer[i++] = '\0'; + code = atoi(buffer); + i = 0; + state = 1; + } else if (state == 1 && c == '\n') { + buffer[i++] = '\0'; + response = json::parse(buffer); + break; + } else { + buffer[i++] = c; + } + } + + led.blink(); + } + } + return code; +} +\ No newline at end of file diff --git a/5g-client/include/config.h b/5g-client/include/config.h @@ -10,6 +10,7 @@ // -*- behaviour settings -*- #define remoteBaud 115200 // baud-rate of usb-serial #define modemBaud 115200 // baud-rate of modem-serial +#define remoteForce true // do not try connect to modem #define remoteFirstTimeout 5.0 // seconds to wait for the first timeout #define remoteTimeout 1.0 // seconds to wait for remote to timeout #define lineBuffer 512 // buffer-size (bytes) to use to store lines @@ -20,12 +21,14 @@ #define eventDebug true // print '+'-events #define lineDebug false // print each line to debug #define blockDebug true // print if command is blocking -#define usbWait true // wait for a usb-connection +#define blinkInterval 0.25 // seconds to wait for blink +#define gpsTimeout 10 // seconds to gps-timeout // -*- sim settings -*- -#define macAddress "CAFEBABE01234567" // the boards mac-address -#define simPin "0000" // PIN of the sim -#define simAPN "lpwa.vodafone.iot" // APN-network of the sim +#define macAddress "CAFEBABE01234567" // the boards mac-address +#define simPin "0000" // PIN of the sim +#define simAPN "lpwa.vodafone.iot" // APN-network of the sim +#define apiHostname "muizenval.tk" // -*- prefixes -*- #define prefixInfo "info | " diff --git a/5g-client/include/http.h b/5g-client/include/http.h @@ -0,0 +1,28 @@ +#pragma once + +#include <Arduino_JSON.h> + + +typedef JSONVar json; + +extern json null_response; + +struct http_client { + enum method { + HTTP_GET, + HTTP_POST + }; + + protected: + bool remote = false; + + void fallback(); + + public: + bool ready = false; + + void begin(); + + int send(method method, const char* endpoint, const char* body = "{}", json& response = null_response); + int send(method method, const char* endpoint, json body = nullptr, json& response = null_response); +}; +\ No newline at end of file diff --git a/5g-client/include/led.h b/5g-client/include/led.h @@ -0,0 +1,26 @@ +#pragma once + + +struct status_led { + enum color { + COLOR_NONE, + COLOR_RED, + COLOR_GREEN, + COLOR_BLUE, + COLOR_YELLOW, + COLOR_CYAN, + COLOR_MAGENTA, + COLOR_WHITE, + }; + + protected: + color color0 = COLOR_NONE, color1 = COLOR_NONE; + + public: + void begin(); + void set(color c); + void set(color c0, color c1); + void blink(); +}; + +extern status_led led; +\ No newline at end of file diff --git a/5g-client/led.ino b/5g-client/led.ino @@ -0,0 +1,51 @@ +#include "include/config.h" +#include "include/led.h" + +static bool colors[][3] = { + [status_led::COLOR_NONE] = { 0, 0, 0 }, + [status_led::COLOR_RED] = { 1, 0, 0 }, + [status_led::COLOR_GREEN] = { 0, 1, 0 }, + [status_led::COLOR_BLUE] = { 0, 0, 1 }, + [status_led::COLOR_YELLOW] = { 1, 1, 0 }, + [status_led::COLOR_CYAN] = { 0, 1, 1 }, + [status_led::COLOR_MAGENTA] = { 1, 0, 1 }, + [status_led::COLOR_WHITE] = { 1, 1, 1 }, +}; + +static void writeLED(bool red, bool green, bool blue) { + digitalWrite(LED_RED, !red); + digitalWrite(LED_GREEN, !green); + digitalWrite(LED_BLUE, !blue); +} + +void status_led::begin() { + pinMode(LED_RED, OUTPUT); + pinMode(LED_GREEN, OUTPUT); + pinMode(LED_BLUE, OUTPUT); +} + +void status_led::set(color c) { + color0 = color1 = c; +} + +void status_led::set(color c0, color c1) { + color0 = c0; + color1 = c1; +} + +void status_led::blink() { + static int last = 0; + static bool first = false; + int now = millis(); + + if (now - last > blinkInterval * 1000) { + if (first) + writeLED(colors[color0][0], colors[color0][1], colors[color0][2]); + else + writeLED(colors[color1][0], colors[color1][1], colors[color1][2]); + first = !first; + last = now; + } +} + +status_led led; +\ No newline at end of file diff --git a/old_client.ino b/old_client.ino @@ -0,0 +1,175 @@ +#include "include/config.h" +#include "include/http.h" +#include "include/modem.h" +#include "include/remote.h" + +#include <Sodaq_LSM303AGR.h> +#include <Sodaq_UBlox_GPS.h> +#include <Wire.h> + +#define ADC_AREF 3.3f +#define BATVOLT_R1 4.7f +#define BATVOLT_R2 10.0f +#define BATVOLT_PIN BAT_VOLT + +#define statusDelay 0.5 // seconds + +#define batteryFactor (0.978 * (BATVOLT_R1 / BATVOLT_R2 + 1) / ADC_AREF) + +http_client http; + +sara_modem modem; +Sodaq_LSM303AGR accel; +serial_remote remote; + +void setup() { + // -*- hardware initiation -*- + + usbSerial.begin(remoteBaud); + while (usbWait && !usbSerial) + ; + + pinMode(BATVOLT_PIN, INPUT); + pinMode(CHARGER_STATUS, INPUT); + + // modem.init(); + remote.begin(); + + Wire.begin(); + delay(1000); + sodaq_gps.init(GPS_ENABLE); + + accel.rebootAccelerometer(); + delay(1000); + + // Enable the Accelerometer + accel.enableAccelerometer(); + + remote.connect("127.0.0.1", 5000); + + // modem.send("ATE0"); // disable command-echo + + // if (modem.send("AT+CPIN=\"" SIM_PIN "\"") == sara_modem::COMMAND_ERROR) { + // // usbSerial.println("[EROR] sim can't be unlocked, wrong PIN"); + // return; + // } + // usbSerial.println(prefixInfo "sim successful unlocked"); + /* + + modem.send("AT+CPSMS=0"); // Disable Power Saving Mode + modem.send("AT+CEDRXS=0"); // Disable eDRX + // usbSerial.println(prefixInfo "disabled power safe"); + + + // -*- internet initialization -*- + char info[100]; + + modem.send("AT+CFUN=15", sara_modem::COMMAND_BLOCK); // Reset the module + modem.send("AT+UMNOPROF=1", sara_modem::COMMAND_BLOCK); // Set MNO profile (1=automatic,100=standard europe) + modem.send("AT+URAT?", info); + // usbSerial.print(prefixInfo "urat: "); + // usbSerial.println(info); + modem.send("AT+URAT=8", sara_modem::COMMAND_IGNORE); // Set URAT to LTE-M/NB-IOT + modem.send("AT+CEREG=3", sara_modem::COMMAND_IGNORE); // Enable URCs + modem.send("AT+CGDCONT=1,\"IP\",\"" simAPN "\"", sara_modem::COMMAND_BLOCK); // Set the APN + modem.send("AT+CFUN=1"); // enable radio + modem.send("AT+COPS=0,2", sara_modem::COMMAND_BLOCK); // Autoselect the operator + + // usbSerial.print(prefixInfo "waiting for connection"); + + char response[100]; + + // Check Siganl strenght, repeat till you have a valid CSQ (99,99 means no signal) + while (modem.send("AT+CSQ", response, sara_modem::COMMAND_SILENT) == sara_modem::COMMAND_OK && !strcmp(response, "+CSQ: 99,99")) { + delay(1000); + // usbSerial.print("."); + } + + // Wait for attach, 1 = attached + while (modem.send("AT+CGATT?", response, sara_modem::COMMAND_SILENT) == sara_modem::COMMAND_OK && strcmp(response, "+CGATT: 1")) { + delay(1000); + // usbSerial.print("."); + } + // usbSerial.println(); + + // usbSerial.println(prefixInfo "connected!"); + + // -*- server connection -*- + + + //AT+UHTTP=0,0,"86.92.67.21" + //AT+UHTTP=0,5,80 + //AT+UHTTPC=0,5,"/api/search_connect","","TEST!",1 + + modem.send("AT+UHTTP=0,0,\"86.92.67.21\""); + modem.send("AT+UHTTP=0,5,80"); + modem.send("AT+UHTTPC=0,5,\"/api/search_connect\",\"\",\"TEST!\",1");*/ + + + // usbSerial.println(prefixInfo "initiation completed, starting remote:"); +} + + +void loop() { + /* // -*- remote for custom commands -*- + while (usbSerial.available()) + modemSerial.write(usbSerial.read()); + + while (modemSerial.available()) + usbSerial.write(modemSerial.read()); + + char buffer[512]; + gps.read(buffer); + + if (buffer[0] != '\0') { + // usbSerial.print("gps | "); + // usbSerial.println(buffer); + }*/ + + static int last = 0; + int now = millis(); + + static double lat = 0, lon = 0, accuracy = 0; + + if (now - last > statusDelay * 1000) { + if (sodaq_gps.scan(true, 10000)) { + lat = sodaq_gps.getLat(); + lon = sodaq_gps.getLon(); + accuracy = 1.0 / sodaq_gps.getHDOP() * 100; + // -> 100% the best, 0% the worst + // usbSerial.print(sodaq_gps.getLat(), 13); + // usbSerial.print(" - "); + // usbSerial.print(sodaq_gps.getLon(), 13); + // usbSerial.print(" ~ accuracy "); + // usbSerial.print(1.0 / sodaq_gps.getHDOP() * 100, 1); + // usbSerial.println("%"); + } + + serial_remote::http_packet req, res; + req.method = "POST"; + req.endpoint = "/api/update"; + req.body["charging"] = (bool) digitalRead(CHARGER_STATUS); + req.body["latitude"] = lat; + req.body["longitude"] = lon; + req.body["accuracy"] = accuracy; + req.body["battery"] = batteryVoltage(); + req.body["temperature"] = temperature(); + + remote.send(req); + last = now; + } + + // usbSerial.print(batteryVoltage()); + // usbSerial.println("V battery"); + + // usbSerial.print(temperature()); + // usbSerial.println(" deg celsius"); +} + +int temperature() { + return accel.getTemperature(); +} + +int batteryVoltage() { + return batteryFactor * (float) analogRead(BATVOLT_PIN); +} diff --git a/remote.py b/remote.py @@ -7,49 +7,21 @@ import json if len(sys.argv) < 2: print(f'{sys.argv[0]} <serial>') -server_address = '' -serial_port = serial.Serial(port=sys.argv[2], baudrate=115200) +server_address = 'localhost', 5000 +serial_port = serial.Serial(port=sys.argv[1], baudrate=115200) -client = None - -def handle(req): - global client - - if 'command' not in req: - return 'command ommitted' - elif req['command'] == 'hello': - return None - elif req['command'] == 'connect': - client = HTTPConnection(req['host'], req['port']) - elif req['command'] == 'send': - headers = req['headers'] or {} - headers['Content-Type'] = 'application/json' - if client is None: - return 'not connected' - client.request(req['method'], req['endpoint'], json.dumps(req['body']), headers) - res = client.getresponse() - return { 'code': res.status, 'headers': dict(res.headers), 'body': json.load(res) } - else: - return 'unknown command' +client = HTTPConnection(server_address[0], server_address[1]) while serial_port.is_open: try: - req = json.loads(serial_port.readline()) - res = handle(req) - except Exception as e: - req = '<error>' - res = { 'error': 'internal', 'description': str(e) } - print('-> ' + repr(req)) + method, endpoint, body = serial_port.readline().decode().split(' ', 2) + print(f'-> {method} {endpoint} {body}') - if type(res) == str: - res = { "error": res } - elif res is None: - res = { "error": None } - elif type(res) == dict: - if 'error' not in res: - res['error'] = None - else: - res = { "error": None, "value": res } - print('<- ' + repr(res)) + client.request(method, endpoint, body) + res = client.getresponse() + response = res.read().decode() + print(f'<- {res.status} {response}') - serial_port.write((json.dumps(res) + '\n').encode()) + serial_port.write(f'{res.status} {response}'.encode()) + except: + serial_port.write(b'0 {}\n') diff --git a/test-server.py b/test-server.py @@ -14,16 +14,15 @@ temperature = 0 def update(): global latitude, longitude, accuracy, battery, temperature - if request.is_json: - req = cast(dict, request.get_json()) - latitude = req['latitude'] - longitude = req['longitude'] - accuracy = req['accuracy'] - battery = req['battery'] - temperature = req['temperature'] - return {} - - return {"error": "request must be json"}, 415 + req = request.get_json(True) + if not req: + return + latitude = req['latitude'] + longitude = req['longitude'] + accuracy = req['accuracy'] + battery = req['battery'] + temperature = req['temperature'] + return {} @app.get("/") def index():