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") DEBUG_TIMER = config.getboolean("debug", "timer") 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 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() 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() if DEBUG_TIMER: print("Turning " + 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() if DEBUG_TIMER: print("Turning " + 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()