citizenwatt-refactor/base/process.py

110 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
import datetime
import json
import os
import stat
import struct
import sys
import time
from libcitizenwatt import database
from libcitizenwatt import tools
from Crypto.Cipher import AES
from libcitizenwatt.config import Config
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
def get_rate_type(db):
"""Returns "day" or "night" according to current time
"""
user = db.query(database.User).filter_by(is_admin=1).first()
now = datetime.datetime.now()
now = 3600 * now.hour + 60 * now.minute
if user is None:
return -1
elif user.end_night_rate > user.start_night_rate:
if now > user.start_night_rate and now < user.end_night_rate:
return 1
else:
return 0
else:
if now > user.start_night_rate or now < user.end_night_rate:
return 1
else:
return 0
def get_cw_sensor():
"""Returns the citizenwatt sensor object or None"""
db = create_session()
sensor = (db.query(database.Sensor)
.filter_by(name="CitizenWatt")
.first())
db.close()
return sensor
# Configuration
config = Config()
# DB initialization
database_url = (config.get("database_type") + "://" + config.get("username") +
":" + config.get("password") + "@" + config.get("host") + "/" +
config.get("database"))
engine = create_engine(database_url, echo=config.get("debug"))
create_session = sessionmaker(bind=engine)
database.Base.metadata.create_all(engine)
sensor = get_cw_sensor()
while not sensor or not sensor.aes_key:
tools.warning("Install is not complete ! " +
"Visit http://citizenwatt.local first.")
time.sleep(1)
sensor = get_cw_sensor()
key = json.loads(sensor.aes_key)
key = struct.pack("<16B", *key)
try:
assert(stat.S_ISFIFO(os.stat(config.get("named_fifo")).st_mode))
except (AssertionError, FileNotFoundError):
sys.exit("Unable to open fifo " + config.get("named_fifo") + ".")
try:
with open(config.get("named_fifo"), 'rb') as fifo:
while True:
measure = fifo.read(16)
print("New encrypted packet:" + str(measure))
decryptor = AES.new(key, AES.MODE_ECB)
measure = decryptor.decrypt(measure)
measure = struct.unpack("<HHHLlH", measure)
print("New incoming measure:" + str(measure))
power = measure[0]
voltage = measure[1]
battery = measure[2]
timer = measure[3]
if(sensor.last_timer and sensor.last_timer > 0 and
sensor.last_timer < 4233600000 and
timer < sensor.last_timer):
tools.warning("Invalid timer in the last packet, skipping it")
else:
db = create_session()
measure_db = database.Measures(sensor_id=sensor.id,
value=power,
timestamp=datetime.datetime.now().timestamp(),
night_rate=get_rate_type(db))
db.add(measure_db)
sensor.last_timer = timer
(db.query(database.Sensor)
.filter_by(name="CitizenWatt")
.update({"last_timer": sensor.last_timer}))
db.commit()
print("Saved successfully.")
except KeyboardInterrupt:
pass