110 lines
3.4 KiB
Python
Executable File
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
|