Files @ 653da092aa96
Branch filter:

Location: HydroBot/hydrobot-software/hydrobot.py - annotation

matthewreed
Added inteval-based scheduling
d1142fbbace4
1aa7eed26cdb
1aa7eed26cdb
22b6999f8bdd
22b6999f8bdd
653da092aa96
a5b830d92afd
d1142fbbace4
d1142fbbace4
1aa7eed26cdb
a5b830d92afd
a5b830d92afd
a5b830d92afd
a5b830d92afd
22b6999f8bdd
a5b830d92afd
d1142fbbace4
22b6999f8bdd
a5b830d92afd
1aa7eed26cdb
1aa7eed26cdb
d1142fbbace4
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
1aa7eed26cdb
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
22b6999f8bdd
daaed5044a8c
daaed5044a8c
daaed5044a8c
1aa7eed26cdb
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
d1142fbbace4
daaed5044a8c
daaed5044a8c
daaed5044a8c
1aa7eed26cdb
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
a5b830d92afd
a5b830d92afd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
1aa7eed26cdb
daaed5044a8c
daaed5044a8c
a5b830d92afd
a5b830d92afd
a5b830d92afd
a5b830d92afd
a5b830d92afd
a5b830d92afd
a5b830d92afd
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
a5b830d92afd
a5b830d92afd
22b6999f8bdd
22b6999f8bdd
653da092aa96
22b6999f8bdd
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
653da092aa96
1aa7eed26cdb
1aa7eed26cdb
d1142fbbace4
daaed5044a8c
daaed5044a8c
daaed5044a8c
daaed5044a8c
a5b830d92afd
653da092aa96
a5b830d92afd
d1142fbbace4
1aa7eed26cdb
1aa7eed26cdb
1aa7eed26cdb
1aa7eed26cdb
1aa7eed26cdb
1aa7eed26cdb
1aa7eed26cdb
import sys
import time
import _thread
import ast
import configparser
import datetime
from canard import can, messaging
from canard.hw import socketcan
from canard.file import jsondb
from influxdb import InfluxDBClient
from apscheduler.schedulers.background import BackgroundScheduler

#TODO
#fix temperature offset
#database series helper
#database time interval logging

config = configparser.ConfigParser(allow_no_value = True)
config.read("hydrobot.conf")
DEBUG_CAN = config.getboolean("debug", "can")
DEBUG_CAN_DETAIL = config.getboolean("debug", "can_detail")

class Database:
    
    def __init__(self):
        host = config.get("database", "host")
        port = config.get("database", "port")
        username = config.get("database", "username")
        password = config.get("database", "password")
        database = config.get("database", "database")
        self.name = config.get("system", "name")
        self.client = InfluxDBClient(host, port, username, password, database)

    def log_data(self, msgdb, message):
        if message == msgdb.AirSense:
            json_body = [
                {
                    "measurement": self.name + "_air_temp",
                    "fields": {
                        "value": (float)(message.Temperature.value)
                    }
                },
                {
                    "measurement": self.name + "_air_humidity",
                    "fields": {
                        "value": (float)(message.Humidity.value)
                    }
                },
                {
                    "measurement": self.name + "_air_pressure",
                    "fields": {
                        "value": (float)(message.Pressure.value)
                    }
                }
            ]
            self.client.write_points(json_body)
        if message == msgdb.RelayDriveIn:
            json_body = [
                {
                    "measurement": self.name + "_input_1",
                    "fields": {
                        "value": (float)(message.Input1.value)
                    }
                },
                {
                    "measurement": self.name + "_input_2",
                    "fields": {
                        "value": (float)(message.Input2.value)
                    }
                },
                {
                    "measurement": self.name + "_input_3",
                    "fields": {
                        "value": (float)(message.Input3.value)
                    }
                },
                {
                    "measurement": self.name + "_input_4",
                    "fields": {
                        "value": (float)(message.Input4.value)
                    }
                }
            ]
            self.client.write_points(json_body)


class CanBus:
    
    def __init__(self, database):
        
        self.database = database

        self.dev = socketcan.SocketCanDev("can0")
        
        parser = jsondb.JsonDbParser()
        self.msgdb = parser.parse('hydrobot_can.json')
        
        self.temp_msg = self.msgdb.AirSense
        self.relay_msg = self.msgdb.RelayDriveIn
        self.relay_send_msg = self.msgdb.RelayDriveOut
        
    def start(self):
        self.dev.start()
        
    def start_receive(self):
        _thread.start_new_thread(self.process_can, ())

    def process_can(self):
        while True:
            frame = self.dev.recv()
            message = self.msgdb.decode(frame)
            if message:
                if DEBUG_CAN:
                    print("Received CAN message! ID: " + hex(message.id))
                for s in message._signals.values():
                    if DEBUG_CAN_DETAIL:
                        print(s)
                        print(s.value)
                    self.database.log_data(self.msgdb, message)
                
    def send_can(self):
        self.relay_send_msg.Nothing.value = 0
        if self.relay_send_msg.Output1.value == 0:
            self.relay_send_msg.Output1.value = 1
        else:
            self.relay_send_msg.Output1.value = 0
        self.relay_send_msg.Output2.value = 1
        self.relay_send_msg.Output3.value = 1
        self.relay_send_msg.Output4.value = 1
        if DEBUG_CAN:
            print("Send CAN message! ID: " + hex(self.relay_send_msg.id))
        if DEBUG_CAN_DETAIL:
            print(self.relay_send_msg)
        self.dev.send(self.relay_send_msg.encode())
        
    def set_output(self, module, output, state):
        msg = self.msgdb.lookup_message(module)
        msg.lookup_signal(output).value = state
        #print(msg)
        self.dev.send(msg.encode())
        
class Scheduler:
    
    def __init__(self, canbus):
        self.canbus = canbus
        self.apscheduler = BackgroundScheduler()
        
    def start(self):
        self.apscheduler.start()
        
        for section in config.sections():
            if "timer" in section:
                items = config.items(section)
                for item in items:
                    if item[0] == 'trigger':
                        trigger = item[1]
                    if item[0] == 'module':
                        module = item[1]
                    if item[0] == 'output':
                        output = item[1]
                    if item[0] == 'on_time':
                        on_time = ast.literal_eval(item[1])
                    if item[0] == 'off_time':
                        off_time = ast.literal_eval(item[1])
                    if item[0] == 'on_duration':
                        on_duration = ast.literal_eval(item[1])
                    if item[0] == 'off_duration':
                        off_duration = ast.literal_eval(item[1])
                if trigger == 'cron':
                    self.apscheduler.add_job(self.canbus.set_output, trigger, [module, output, 1], day = on_time[0], day_of_week = on_time[1], hour = on_time[2], minute = on_time[3], second = on_time[4])
                    self.apscheduler.add_job(self.canbus.set_output, trigger, [module, output, 0], day = off_time[0], day_of_week = off_time[1], hour = off_time[2], minute = off_time[3], second = off_time[4])
                if trigger == 'interval':
                    self.apscheduler.add_job(self.interval_off, trigger, [module, output, section + "_off", section + "_on", on_duration], id = section + "_off", weeks = off_duration[0], days = off_duration[1], hours = off_duration[2], minutes = off_duration[3], seconds = off_duration[4])
                    timer = self.apscheduler.add_job(self.interval_on, trigger, [module, output, section + "_off", section + "_on", off_duration], id = section + "_on", weeks = on_duration[0], days = on_duration[1], hours = on_duration[2], minutes = on_duration[3], seconds = on_duration[4])
                    timer.pause()
                    print(off_duration[4])
                    print(on_duration[4])
        
        
    def interval_off(self, module, output, timer_off, timer_on, on_duration):
        self.canbus.set_output(module, output, 1)
        self.apscheduler.get_job(timer_on).reschedule("interval", weeks = on_duration[0], days = on_duration[1], hours = on_duration[2], minutes = on_duration[3], seconds = on_duration[4])
        self.apscheduler.get_job(timer_on).resume()
        self.apscheduler.get_job(timer_off).pause()
        print("turning on " + timer_on + "! " + str(datetime.datetime.now().time()))
        
    def interval_on(self, module, output, timer_off, timer_on, off_duration):
        self.canbus.set_output(module, output, 0)
        self.apscheduler.get_job(timer_off).reschedule("interval", weeks = off_duration[0], days = off_duration[1], hours = off_duration[2], minutes = off_duration[3], seconds = off_duration[4])
        self.apscheduler.get_job(timer_off).resume()
        self.apscheduler.get_job(timer_on).pause()
        print("turning off " + timer_off + "! " + str(datetime.datetime.now().time()))
    
def func():
    print(1)
    

def main():
    
    database = Database()
    canbus = CanBus(database)
    canbus.start()
    canbus.start_receive()
    
    scheduler = Scheduler(canbus)
    scheduler.start()

    while True:
        
        time.sleep(1)
        

if __name__ == "__main__":
    main()