diff --git a/Dockerfile b/Dockerfile index 6515679..39816f3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ RUN pip install --no-cache-dir --upgrade pip && \ pip install --no-cache-dir -r requirements.txt COPY . . -CMD ["python", "./main.py"] \ No newline at end of file +CMD ["python", "-m", "main"] \ No newline at end of file diff --git a/README.md b/README.md index b63008c..11f81d7 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,19 @@ Requests data from MyStrom switch and stores in sql database. ## Environment Variables -`SQL_URL` - the URL for database, e.g. `mysql+pymysql://user:password@host:3306/databsae` +`SQL_URL` - the URL for database, e.g. `mysql+pymysql://user:password@host:3306/database` + +## Run +### With python +```sh +export SQL_URL=mysql+pymysql://user:password@host:3306/database +python -m main +``` + +### With Docker Container +```sh +docker run \ + --name mystrom-python \ + -e "SQL_URL=mysql+pymysql://user:password@host:3306/database" \ + ghcr.io/maexled/mystrom-python:master +``` diff --git a/base.py b/base.py new file mode 100644 index 0000000..7de8322 --- /dev/null +++ b/base.py @@ -0,0 +1,17 @@ +import os + +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + +sql_url = os.environ['SQL_URL'] +engine = create_engine(sql_url) +# use session_factory() to get a new Session +_SessionFactory = sessionmaker(bind=engine) + +Base = declarative_base() + + +def session_factory(): + Base.metadata.create_all(engine) + return _SessionFactory() \ No newline at end of file diff --git a/main.py b/main.py index f113011..e120a39 100644 --- a/main.py +++ b/main.py @@ -1,50 +1,16 @@ import schedule import time -from datetime import datetime, timezone, timedelta import requests import json -import os -from sqlalchemy import Column, Integer, Float, String, DateTime, ForeignKey -import sqlalchemy as db -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import relationship, backref, sessionmaker, joinedload +import threading -Base = declarative_base() +from base import Base, session_factory -class MystromDevice(Base): - - __tablename__ = 'devices' - - id = Column(Integer, primary_key=True) - - name = Column(String(16)) - ip = Column(String(16)) - - # Lets us print out a user object conveniently. - def __repr__(self): - return "" % ( - self.id, self.name, self.ip) - -class MystromResult(Base): - - __tablename__ = 'results' - - id = Column(Integer, primary_key=True) - - device_id = Column(Integer, ForeignKey('devices.id')) - - power = Column(Float) - ws = Column(Float) - relay = Column(Integer) - temperature = Column(Float) - date = Column(DateTime(timezone=True), default=datetime.now) - - # Lets us print out a user object conveniently. - def __repr__(self): - return "" % ( - self.device_id, self.power, self.ws, self.relay, self.temperature, self.date) +from models.mystrom_device import MystromDevice +from models. mystrom_result import MystromResult +@schedule.repeat(schedule.every(1).minutes) def trigger(): for device in devices: request_data_and_store(device) @@ -55,32 +21,18 @@ def get_devices(): def request_data_and_store(device): response = requests.get(f'http://{device.ip}/report') - json_response = json.loads(response.text) - mystrom_result = json_result_to_object(json_response, device) + response = json.loads(response.text) + mystrom_result = MystromResult(device_id=device.id, power=response["power"], ws=response["Ws"], relay=response["relay"], temperature=response["temperature"]) session.add(mystrom_result, device) session.commit() -def json_result_to_object(json, device): - return MystromResult(device_id=device.id, power=json["power"], ws=json["Ws"], relay=json["relay"], temperature=json["temperature"]) - if __name__ == '__main__': - sql_url = os.environ['SQL_URL'] - engine = db.create_engine(sql_url) - connection = engine.connect() - - Base.metadata.create_all(engine) - - Session = sessionmaker(bind=engine) - session = Session() - + session = session_factory() devices = get_devices() - schedule.every(1).minutes.do(trigger) - while True: - # Checks whether a scheduled task # is pending to run or not schedule.run_pending() - time.sleep(1) \ No newline at end of file + time.sleep(1) diff --git a/models/mystrom_device.py b/models/mystrom_device.py new file mode 100644 index 0000000..51ff929 --- /dev/null +++ b/models/mystrom_device.py @@ -0,0 +1,16 @@ +from base import Base +from sqlalchemy import Column, Integer, String + +class MystromDevice(Base): + + __tablename__ = 'devices' + + id = Column(Integer, primary_key=True) + + name = Column(String(16)) + ip = Column(String(16)) + + # Lets us print out a user object conveniently. + def __repr__(self): + return "" % ( + self.id, self.name, self.ip) \ No newline at end of file diff --git a/models/mystrom_result.py b/models/mystrom_result.py new file mode 100644 index 0000000..c83bef5 --- /dev/null +++ b/models/mystrom_result.py @@ -0,0 +1,22 @@ +from base import Base +from sqlalchemy import Column, Integer, Float, DateTime, ForeignKey +from datetime import datetime + +class MystromResult(Base): + + __tablename__ = 'results' + + id = Column(Integer, primary_key=True) + + device_id = Column(Integer, ForeignKey('devices.id')) + + power = Column(Float) + ws = Column(Float) + relay = Column(Integer) + temperature = Column(Float) + date = Column(DateTime(timezone=True), default=datetime.now) + + # Lets us print out a user object conveniently. + def __repr__(self): + return "" % ( + self.device_id, self.power, self.ws, self.relay, self.temperature, self.date) \ No newline at end of file