t
This commit is contained in:
parent
bf4b02902b
commit
f468332843
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "sql_as_rest_api"]
|
||||
path = sql_as_rest_api
|
||||
url = https://github.com/moll-re/sql_as_rest_api
|
23
README.md
23
README.md
@ -6,18 +6,29 @@ Just like AIO-coolers, this little program aims to tackle many problems at once.
|
||||
## What it mainly does
|
||||
* chat-bot (via telegram)
|
||||
* clock and basic display (via LED-Matrix (size to taste))
|
||||
* dashboard (via external browser)
|
||||
* measure ambient temperatures
|
||||
* Logging of the previous actions
|
||||
|
||||
|
||||
### Chatbot
|
||||
Periodically calls the telegram api and reacts to sent commands. Also handles basic calls to the hardware: it allows you to control certain aspects of the clock.
|
||||
|
||||
TODO: advanced analytics of the chat (grafana)
|
||||
|
||||
## Clock
|
||||
### Clock
|
||||
Server/Client which send/receive the output to show on the clock. Normally this is just a combination of time + weather. But special output can be triggered by the user.
|
||||
|
||||
## Dashboard
|
||||
Shows basic info of the program and other useful things.
|
||||
### Ambient measurements
|
||||
Logs temperature, luminosity, humidity to a remote database. This information is then displayed in `moll.re`.
|
||||
|
||||
TODO: show advanced host stats (cpu/mem/...)
|
||||
TODO: Log relevant worker info such as cpu activity and network connectivity.
|
||||
|
||||
|
||||
## Submodules
|
||||
This program makes use of git submodules, namely `sql_as_rest_api`. This implies additional steps when cloning this repo:
|
||||
|
||||
* CLone **this** repo to your machine.
|
||||
* Enter the repo
|
||||
* Type `git submodule init` which creates a `.gitmodules` file
|
||||
* Type `git submodule update` which fetches the newest version of these submodules
|
||||
|
||||
TODO Describe dev process
|
@ -1,8 +1,5 @@
|
||||
from .template import *
|
||||
|
||||
import datetime
|
||||
import requests
|
||||
|
||||
NAME, NEW, ACTION, ITEMADD, ITEMREMOVE = range(5)
|
||||
|
||||
|
||||
@ -41,6 +38,7 @@ class Lists(BotFunc):
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
super().entry_point(update, context)
|
||||
# TODO Change DB
|
||||
lists = self.db.lists.select()
|
||||
sl = [l.name for l in lists]
|
||||
keyboard = [[InlineKeyboardButton(k, callback_data="list-"+k)] for k in sl] + [[InlineKeyboardButton("New list", callback_data="new")]]
|
||||
|
@ -62,6 +62,7 @@ class Status(BotFunc):
|
||||
u = str(self.get_ngrok_url())
|
||||
message += "URL: [" + u + "](" + u + ")\n"
|
||||
|
||||
# TODO new DB
|
||||
tot_r = self.db.chats.select().where(self.db.chats.read == True).count()
|
||||
message += "Total messages read: `{}`\n".format(tot_r)
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import logging
|
||||
import datetime
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, ParseMode
|
||||
from telegram.ext import Updater, CommandHandler, CallbackQueryHandler, CallbackContext, MessageHandler, Filters
|
||||
from telegram.ext import (
|
||||
@ -21,20 +20,20 @@ class BotFunc():
|
||||
self.db = db
|
||||
|
||||
|
||||
def log_activity(self, **kwargs):
|
||||
# mark that a new command has been executed
|
||||
try:
|
||||
data = self.db.chats(
|
||||
time=datetime.datetime.now(),
|
||||
**kwargs
|
||||
)
|
||||
# kwargs can look like
|
||||
# receive=True,
|
||||
# execute=True,
|
||||
# send=False,
|
||||
data.save()
|
||||
except Exception as e:
|
||||
self.logger.error("sql error: {}".format(e))
|
||||
# def log_activity(self, **kwargs):
|
||||
# # mark that a new command has been executed
|
||||
# try:
|
||||
# data = self.db.chats(
|
||||
# time=datetime.datetime.now(),
|
||||
# **kwargs
|
||||
# )
|
||||
# # kwargs can look like
|
||||
# # receive=True,
|
||||
# # execute=True,
|
||||
# # send=False,
|
||||
# data.save()
|
||||
# except Exception as e:
|
||||
# self.logger.error("sql error: {}".format(e))
|
||||
|
||||
def entry_point(self, update: Update, context: CallbackContext) -> None:
|
||||
if update.message.text:
|
||||
|
@ -1,44 +1,26 @@
|
||||
from datetime import datetime
|
||||
from peewee import *
|
||||
# from playhouse.pool import PooledMySQLDatabase
|
||||
from playhouse.shortcuts import ReconnectMixin
|
||||
import logging
|
||||
import json
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def create_tables(db):
|
||||
db.create_tables([SensorMetric, ChatMetric, ErrorMetric, List])
|
||||
|
||||
db = DatabaseProxy()
|
||||
# set the nature of the db at runtime
|
||||
|
||||
class ReconnectDataBase(ReconnectMixin, MySQLDatabase):
|
||||
pass
|
||||
|
||||
|
||||
class DBModel(Model):
|
||||
# specific to the above DB
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
def save(self):
|
||||
# fail-safe writing of the db-object. Usually threaded because the caller is threaded
|
||||
try:
|
||||
# db.connect()
|
||||
super().save()
|
||||
# db.close()
|
||||
except Exception as e:
|
||||
logger.error("Could not write to db. Dropping content of {}".format(self.__class__.__name__))
|
||||
logger.error(e)
|
||||
# db.atomic().rollback()
|
||||
|
||||
# def get(self, *query, **filters):
|
||||
# try:
|
||||
# return super().get(*query, **filters)
|
||||
# except Exception as e:
|
||||
# logger.error("Error while executing get: {}".format(e))
|
||||
# print(query, filters)
|
||||
|
||||
|
||||
class Metric(DBModel):
|
||||
time = DateTimeField()
|
||||
time = DateTimeField(default = datetime.now())
|
||||
|
||||
|
||||
|
||||
### Actual metrics:
|
||||
@ -48,24 +30,26 @@ class SensorMetric(Metric):
|
||||
temperature = IntegerField()
|
||||
humidity = IntegerField()
|
||||
luminosity = IntegerField()
|
||||
default = {"temperature": 100, "humidity": 100, "luminosity": 100}
|
||||
|
||||
|
||||
|
||||
class ChatMetric(Metric):
|
||||
read = BooleanField()
|
||||
send = BooleanField()
|
||||
execute = BooleanField()
|
||||
default = {"read": False, "send": False, "execute": False}
|
||||
|
||||
|
||||
class ErrorMetric(Metric):
|
||||
# same as above
|
||||
error = TextField()
|
||||
default = {"error": "SQL connection broke off"}
|
||||
|
||||
|
||||
class List(DBModel):
|
||||
name = CharField(unique=True)
|
||||
content = TextField() # unlimited length, use to serialise list into
|
||||
default = {"content": "SQL connection broke off"}
|
||||
|
||||
@property
|
||||
def content_as_list(self):
|
||||
return json.loads(self.content)
|
||||
|
||||
def set_content(self, list_content):
|
||||
self.content = json.dumps(list_content)
|
@ -1,116 +0,0 @@
|
||||
from . import models
|
||||
from peewee import *
|
||||
# from playhouse.pool import PooledMySQLDatabase
|
||||
from playhouse.shortcuts import ReconnectMixin
|
||||
import inspect
|
||||
|
||||
from . import keys
|
||||
dbk = keys.db_keys
|
||||
|
||||
|
||||
class ReconnectDataBase(ReconnectMixin, MySQLDatabase):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class DBConnector:
|
||||
"""Create a connection to a remote database and log some quantities that will be visualized otherwhere"""
|
||||
def __init__(self):
|
||||
self.db = models.db
|
||||
|
||||
self.sensors = models.SensorMetric
|
||||
self.chats = models.ChatMetric
|
||||
self.errors = models.ErrorMetric
|
||||
self.lists = models.List
|
||||
|
||||
self.create_tables()
|
||||
|
||||
def create_tables(self):
|
||||
self.db.create_tables([self.sensors, self.chats, self.errors, self.lists])
|
||||
|
||||
|
||||
|
||||
class DataBaseConnector:
|
||||
def __init__(self) -> None:
|
||||
self.db_object = models.ReconnectDataBase(
|
||||
dbk["name"],
|
||||
user=dbk["username"],
|
||||
password=dbk["password"],
|
||||
host=dbk["url"],
|
||||
port=dbk["port"],
|
||||
autorollback=True
|
||||
)
|
||||
models.db.initialize(self.db_object)
|
||||
|
||||
# self.sensors = models.SensorMetric
|
||||
# self.chats = models.ChatMetric
|
||||
# self.errors = models.ErrorMetric
|
||||
# self.lists = models.List
|
||||
## Set as property methods instead
|
||||
|
||||
self.db_object.create_tables([self.sensors, self.chats, self.errors, self.lists])
|
||||
|
||||
@property
|
||||
def sensors(self):
|
||||
self.connect_first()
|
||||
return models.SensorMetric
|
||||
|
||||
@property
|
||||
def chats(self):
|
||||
self.connect_first()
|
||||
return models.ChatMetric
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
self.connect_first()
|
||||
return models.ErrorMetric
|
||||
|
||||
@property
|
||||
def lists(self):
|
||||
self.connect_first()
|
||||
return models.List
|
||||
|
||||
def connect_first(self):
|
||||
# if self.db_object.is_closed():
|
||||
# self.db_object.connect()
|
||||
self.db_object.connect(reuse_if_open=True)
|
||||
|
||||
|
||||
|
||||
|
||||
# def auto_reconnect(func, *args, **kwargs):
|
||||
# return func
|
||||
|
||||
# def classwide_decorator(decorator):
|
||||
# def decorate(cls):
|
||||
# for attr in inspect.getmembers(cls, inspect.ismethod): # there's propably a better way to do this
|
||||
# # TODO: filter init
|
||||
# print(attr)
|
||||
# if callable(getattr(cls, attr)):
|
||||
# setattr(cls, attr, decorator(getattr(cls, attr)))
|
||||
# return cls
|
||||
# return decorate
|
||||
|
||||
# # apply auto_reconnect to every method so that every method first checks the db connection and reconnects if necessary
|
||||
# @classwide_decorator(auto_reconnect)
|
||||
# class DataBaseConnector(ReconnectMixin, MySQLDatabase):
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# super().__init__(
|
||||
# dbk["name"],
|
||||
# user=dbk["username"],
|
||||
# password=dbk["password"],
|
||||
# host=dbk["url"],
|
||||
# port=dbk["port"],
|
||||
# autorollback=True,
|
||||
# *args, **kwargs)
|
||||
|
||||
# models.db.initialize(self)
|
||||
# self.sensors = models.SensorMetric
|
||||
# self.chats = models.ChatMetric
|
||||
# self.errors = models.ErrorMetric
|
||||
# self.lists = models.List
|
||||
|
||||
# self.create_tables([self.sensors, self.chats, self.errors, self.lists])
|
||||
|
||||
# def m1(self): pass
|
||||
# def m2(self, x): pass
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
@ -1 +0,0 @@
|
||||
Subproject commit 1e24c1491d2e80ce9d915b20f434c1e10fab3156
|
20
test.py
20
test.py
@ -1,20 +0,0 @@
|
||||
|
||||
class MyResource:
|
||||
def __enter__(self):
|
||||
print('Entering context.')
|
||||
return self
|
||||
|
||||
def __exit__(self, *exc):
|
||||
print('EXITING context.')
|
||||
|
||||
def try_me(self):
|
||||
print("I work")
|
||||
|
||||
def fun():
|
||||
with MyResource() as a:
|
||||
print('Returning inside with-statement.')
|
||||
return a
|
||||
print('Returning outside with-statement.')
|
||||
|
||||
t =fun()
|
||||
t.try_me()
|
Loading…
x
Reference in New Issue
Block a user