Newer
Older
greenhouse / watering.py
#!/bin/env python3

from pyLoraRFM9x import LoRa, ModemConfig
import time
from collections import namedtuple
from struct import *
import pykka
import paho.mqtt.client as paho
from paho import mqtt
import json
from http.server import HTTPServer, BaseHTTPRequestHandler
from threading import Thread

client = paho.Client(paho.CallbackAPIVersion.VERSION2)
client.connect("stanley")

Watering = namedtuple('Watering', 'voltage moisture pump_speed pump_running errors')
WateringStruct = '<HHB?B'

Command = namedtuple('Command', 'proc arg')
CommandStruct = '<BB'

class WaterActor(pykka.ThreadingActor):
    def __init__(self, client):
        super().__init__()
        self.client = client
        self.cmds = []

    def greenhouse(self, payload):
        try:
            message = Watering._make(unpack(WateringStruct, payload.message))
            to_send = message._asdict()
            to_send['rssi'] = payload.rssi
            to_send['snr'] = payload.snr
            client.publish('events/greenhouse', payload=json.dumps(to_send))
        except Exception as e:
            client.publish('events/greenhouse', payload=str(e))
        if len(self.cmds) > 0:
            time.sleep(0.5)
            for cmd in self.cmds:
                print("Sending: " + str(cmd))
                try:
                    reply = pack(CommandStruct, *cmd)
                    print(reply)
                    lora.send(reply, 2)
                except Exception as e:
                    print(e)
            self.cmds.clear()
            lora.set_mode_rx()

    def queue_command(self, command):
        self.cmds.append(command)

a = WaterActor.start(client).proxy()

class SprinklerHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()
        self.flush_headers()
        if self.path == '/on':
            a.queue_command(Command(1, 248))
            self.wfile.write(bytes("Switching pump on", "utf-8"))
        elif self.path == '/off':
            a.queue_command(Command(0, 0))
            self.wfile.write(bytes("Switching pump off", "utf-8"))

httpd = HTTPServer(('', 80), SprinklerHTTPRequestHandler)

Thread(target=httpd.serve_forever, daemon=True).start()

def on_radio_recv(payload):
    a.greenhouse(payload)

lora = LoRa(1, 24, 1, reset_pin = 25, modem_config=ModemConfig.Bw125Cr45Sf128, tx_power=14, acks=False, freq=868, receive_all=False)
lora.on_recv = on_radio_recv
lora.set_mode_rx()

def on_mqtt_message(client, userdata, message):
    try:
        update = json.loads(message.payload)
        a.queue_update(update)
    except Exception as e:
        client.publish('events/greenhouse', payload=str(e))

client.on_message = on_mqtt_message
client.subscribe("commands/greenhouse")

#client.loop_forever(retry_first_connection=False)
Thread(target=client.loop_forever,
       kwargs={"retry_first_connection": False},
       daemon=True).start()