summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--requirements.txt2
-rwxr-xr-xsrc/camera_node.py2
-rwxr-xr-xsrc/esp32cam_capture_diff_node.py2
-rwxr-xr-xsrc/gpiorelayd.py2
-rw-r--r--src/home/config/__init__.py12
-rw-r--r--src/home/config/_configs.py5
-rw-r--r--src/home/config/config.py170
-rw-r--r--src/home/config/validators/__init__.py2
-rw-r--r--src/home/config/validators/_util.py11
-rw-r--r--src/home/config/validators/_validators.py32
-rw-r--r--src/home/mqtt/_node.py16
-rw-r--r--src/home/mqtt/_wrapper.py8
-rw-r--r--src/home/mqtt/module/ota.py11
-rw-r--r--src/home/mqtt/module/relay.py6
-rw-r--r--src/home/mqtt/module/temphum.py43
-rwxr-xr-xsrc/inverter_bot.py2
-rwxr-xr-xsrc/inverter_mqtt_util.py4
-rwxr-xr-xsrc/ipcam_server.py2
-rwxr-xr-xsrc/mqtt_node_util.py10
-rwxr-xr-xsrc/openwrt_log_analyzer.py2
-rwxr-xr-xsrc/openwrt_logger.py2
-rwxr-xr-xsrc/polaris_kettle_bot.py2
-rwxr-xr-xsrc/polaris_kettle_util.py2
-rwxr-xr-xsrc/pump_bot.py4
-rwxr-xr-xsrc/pump_mqtt_bot.py2
-rwxr-xr-xsrc/relay_mqtt_bot.py49
-rwxr-xr-xsrc/relay_mqtt_http_proxy.py50
-rwxr-xr-xsrc/sensors_bot.py2
-rwxr-xr-xsrc/sensors_mqtt_sender.py58
-rwxr-xr-xsrc/sound_bot.py2
-rwxr-xr-xsrc/sound_node.py2
-rwxr-xr-xsrc/sound_sensor_node.py2
-rwxr-xr-xsrc/sound_sensor_server.py2
-rwxr-xr-xsrc/ssh_tunnels_config_util.py2
-rwxr-xr-xsrc/temphum_mqtt_node.py2
-rwxr-xr-xsrc/temphum_mqtt_receiver.py (renamed from src/sensors_mqtt_receiver.py)23
-rwxr-xr-xsrc/temphumd.py2
-rw-r--r--src/test_new_config.py9
-rwxr-xr-xsrc/web_api.py2
-rw-r--r--systemd/sensors_mqtt_receiver.service4
-rw-r--r--systemd/sensors_mqtt_sender.service13
-rwxr-xr-xtest/mqtt_relay_server_util.py2
-rwxr-xr-xtest/mqtt_relay_util.py2
-rwxr-xr-xtest/test_amixer.py2
-rwxr-xr-xtest/test_api.py2
-rwxr-xr-xtest/test_esp32_cam.py2
-rwxr-xr-xtest/test_inverter_monitor.py2
-rw-r--r--test/test_ipcam_server_cleanup.py2
-rwxr-xr-xtest/test_record_upload.py2
-rwxr-xr-xtest/test_sound_server_api.py2
-rw-r--r--test/test_telegram_aio_send_photo.py2
51 files changed, 332 insertions, 268 deletions
diff --git a/requirements.txt b/requirements.txt
index 46f9b8c..e11d512 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,7 +14,7 @@ apscheduler~=3.9.1
psutil~=5.9.1
aioshutil~=1.1
scikit-image~=0.19.3
-
+cerberus~=1.3.4
# following can be installed from debian repositories
# matplotlib~=3.5.0
diff --git a/src/camera_node.py b/src/camera_node.py
index d175e17..3f2c5a4 100755
--- a/src/camera_node.py
+++ b/src/camera_node.py
@@ -65,7 +65,7 @@ class ESP32CameraNodeServer(MediaNodeServer):
if __name__ == '__main__':
- config.load('camera_node')
+ config.load_app('camera_node')
recorder_kwargs = {}
camera_type = CameraType(config['camera']['type'])
diff --git a/src/esp32cam_capture_diff_node.py b/src/esp32cam_capture_diff_node.py
index 4363e9e..70ebd47 100755
--- a/src/esp32cam_capture_diff_node.py
+++ b/src/esp32cam_capture_diff_node.py
@@ -76,7 +76,7 @@ class ESP32CamCaptureDiffNode:
if __name__ == '__main__':
- config.load('esp32cam_capture_diff_node')
+ config.load_app('esp32cam_capture_diff_node')
loop = asyncio.get_event_loop()
ESP32CamCaptureDiffNode()
diff --git a/src/gpiorelayd.py b/src/gpiorelayd.py
index 85015a7..f1a9e57 100755
--- a/src/gpiorelayd.py
+++ b/src/gpiorelayd.py
@@ -13,7 +13,7 @@ if __name__ == '__main__':
if not os.getegid() == 0:
sys.exit('Must be run as root.')
- config.load()
+ config.load_app()
try:
s = RelayServer(pinname=config.get('relayd.pin'),
diff --git a/src/home/config/__init__.py b/src/home/config/__init__.py
index cc9c091..10c5bd9 100644
--- a/src/home/config/__init__.py
+++ b/src/home/config/__init__.py
@@ -1 +1,11 @@
-from .config import ConfigStore, config, is_development_mode, setup_logging
+from .config import (
+ Config,
+ config,
+ is_development_mode,
+ setup_logging,
+ app_config
+)
+from .validators import validate
+from ._configs import (
+ LinuxBoardsConfig
+) \ No newline at end of file
diff --git a/src/home/config/_configs.py b/src/home/config/_configs.py
new file mode 100644
index 0000000..2f98d06
--- /dev/null
+++ b/src/home/config/_configs.py
@@ -0,0 +1,5 @@
+from .config import ConfigUnit
+
+
+class LinuxBoardsConfig(ConfigUnit):
+ NAME = 'linux_boards'
diff --git a/src/home/config/config.py b/src/home/config/config.py
index 4681685..2d49524 100644
--- a/src/home/config/config.py
+++ b/src/home/config/config.py
@@ -3,45 +3,116 @@ import yaml
import logging
import os
+from . import validators
from os.path import join, isdir, isfile
from typing import Optional, Any, MutableMapping
from argparse import ArgumentParser
from ..util import parse_addr
-def _get_config_path(name: str) -> str:
- formats = ['toml', 'yaml']
+_my_validators = {}
- dirname = join(os.environ['HOME'], '.config', name)
- if isdir(dirname):
- for fmt in formats:
- filename = join(dirname, f'config.{fmt}')
- if isfile(filename):
- return filename
+def _get_validator(name: str) -> Optional[callable]:
+ if hasattr(validators, f'{name}_validator'):
+ return getattr(validators, f'{name}_validator')
+ if name in _my_validators:
+ return _my_validators[name]
+ return None
- raise IOError(f'config not found in {dirname}')
- else:
- filenames = [join(os.environ['HOME'], '.config', f'{name}.{format}') for format in formats]
- for file in filenames:
- if isfile(file):
- return file
+def add_validator(name: str, f: callable):
+ _my_validators[name] = f
- raise IOError(f'config not found')
+class ConfigUnit:
+ NAME = 'dumb'
-class ConfigStore:
data: MutableMapping[str, Any]
+
+ @classmethod
+ def get_config_path(cls, name=None) -> str:
+ if name is None:
+ name = cls.NAME
+ if name is None:
+ raise ValueError('get_config_path: name is none')
+
+ dirnames = (
+ join(os.environ['HOME'], '.config', 'homekit'),
+ '/etc/homekit'
+ )
+
+ for dirname in dirnames:
+ if isdir(dirname):
+ for fmt in ('toml', 'yaml'):
+ filename = join(dirname, f'{name}.{fmt}')
+ if isfile(filename):
+ return filename
+
+ raise IOError(f'config \'{name}\' not found')
+
+ def __init__(self, name=None):
+ self.data = {}
+
+ if self.NAME != 'dumb':
+ self.load_from(self.get_config_path())
+ self.validate()
+
+ elif name is not None:
+ self.NAME = name
+
+ def load_from(self, path: str):
+ if path.endswith('.toml'):
+ self.data = toml.load(path)
+ elif path.endswith('.yaml'):
+ with open(path, 'r') as fd:
+ self.data = yaml.safe_load(fd)
+
+ def validate(self):
+ v = _get_validator(self.NAME)
+ v(self.data)
+
+ def __getitem__(self, key):
+ return self.data[key]
+
+ def __setitem__(self, key, value):
+ raise NotImplementedError('overwriting config values is prohibited')
+
+ def __contains__(self, key):
+ return key in self.data
+
+ def get(self, key: str, default=None):
+ cur = self.data
+ pts = key.split('.')
+ for i in range(len(pts)):
+ k = pts[i]
+ if i < len(pts)-1:
+ if k not in cur:
+ raise KeyError(f'key {k} not found')
+ else:
+ return cur[k] if k in cur else default
+ cur = self.data[k]
+ raise KeyError(f'option {key} not found')
+
+ def get_addr(self, key: str):
+ return parse_addr(self.get(key))
+
+ def items(self):
+ return self.data.items()
+
+
+class Config:
app_name: Optional[str]
+ app_config: ConfigUnit
def __init__(self):
- self.data = {}
self.app_name = None
+ self.app_config = ConfigUnit()
- def load(self, name: Optional[str] = None,
- use_cli=True,
- parser: ArgumentParser = None):
+ def load_app(self,
+ name: Optional[str] = None,
+ use_cli=True,
+ parser: ArgumentParser = None):
self.app_name = name
if (name is None) and (not use_cli):
@@ -75,65 +146,32 @@ class ConfigStore:
log_default_fmt = args.log_default_fmt
if not no_config and path is None:
- path = _get_config_path(name)
-
- if no_config:
- self.data = {}
- else:
- if path.endswith('.toml'):
- self.data = toml.load(path)
- elif path.endswith('.yaml'):
- with open(path, 'r') as fd:
- self.data = yaml.safe_load(fd)
-
- if 'logging' in self:
- if not log_file and 'file' in self['logging']:
- log_file = self['logging']['file']
- if log_default_fmt and 'default_fmt' in self['logging']:
- log_default_fmt = self['logging']['default_fmt']
+ path = ConfigUnit.get_config_path(name=name)
+
+ if not no_config:
+ self.app_config.load_from(path)
+
+ if 'logging' in self.app_config:
+ if not log_file and 'file' in self.app_config['logging']:
+ log_file = self.app_config['logging']['file']
+ if log_default_fmt and 'default_fmt' in self.app_config['logging']:
+ log_default_fmt = self.app_config['logging']['default_fmt']
setup_logging(log_verbose, log_file, log_default_fmt)
if use_cli:
return args
- def __getitem__(self, key):
- return self.data[key]
-
- def __setitem__(self, key, value):
- raise NotImplementedError('overwriting config values is prohibited')
-
- def __contains__(self, key):
- return key in self.data
-
- def get(self, key: str, default=None):
- cur = self.data
- pts = key.split('.')
- for i in range(len(pts)):
- k = pts[i]
- if i < len(pts)-1:
- if k not in cur:
- raise KeyError(f'key {k} not found')
- else:
- return cur[k] if k in cur else default
- cur = self.data[k]
- raise KeyError(f'option {key} not found')
-
- def get_addr(self, key: str):
- return parse_addr(self.get(key))
-
- def items(self):
- return self.data.items()
-
-config = ConfigStore()
+config = Config()
+app_config = config.app_config
def is_development_mode() -> bool:
if 'HK_MODE' in os.environ and os.environ['HK_MODE'] == 'dev':
return True
- return ('logging' in config) and ('verbose' in config['logging']) and (config['logging']['verbose'] is True)
+ return ('logging' in config.app_config) and ('verbose' in config.app_config['logging']) and (config.app_config['logging']['verbose'] is True)
def setup_logging(verbose=False, log_file=None, default_fmt=False):
diff --git a/src/home/config/validators/__init__.py b/src/home/config/validators/__init__.py
new file mode 100644
index 0000000..0e75132
--- /dev/null
+++ b/src/home/config/validators/__init__.py
@@ -0,0 +1,2 @@
+from ._validators import *
+from ._util import validate
diff --git a/src/home/config/validators/_util.py b/src/home/config/validators/_util.py
new file mode 100644
index 0000000..5227c40
--- /dev/null
+++ b/src/home/config/validators/_util.py
@@ -0,0 +1,11 @@
+import inspect
+
+from cerberus import Validator, DocumentError
+
+
+def validate(schema, data):
+ v = Validator(schema)
+ if not v.validate(data):
+ frame = inspect.currentframe().f_back
+ caller_name = frame.f_code.co_name
+ raise DocumentError(f'{caller_name}: failed to validate data: ' + v.errors)
diff --git a/src/home/config/validators/_validators.py b/src/home/config/validators/_validators.py
new file mode 100644
index 0000000..cddc1b0
--- /dev/null
+++ b/src/home/config/validators/_validators.py
@@ -0,0 +1,32 @@
+from ._util import validate
+
+__all__ = [
+ 'linux_boards_validator'
+]
+
+
+def linux_boards_validator(data) -> None:
+ validate({
+ 'type': 'dict',
+ 'valuesrules': {
+ 'type': 'dict',
+ 'schema': {
+ 'mdns': {'type': 'string', 'required': True},
+ 'board': {'type': 'string', 'required': True},
+ 'network': {'type': 'list', 'required': True, 'empty': False},
+ 'ram': {'type': 'integer', 'required': True},
+ 'ext_hdd': {
+ 'type': 'list',
+ 'schema': {
+ 'type': 'dict',
+ 'schema': {
+ 'mountpoint': {'type': 'string', 'required': True},
+ 'size': {'type': 'integer', 'required': True}
+ }
+ },
+ },
+ 'services': {'type': 'list', 'empty': False},
+ 'online': {'type': 'boolean', 'required': True}
+ }
+ }
+ }, data)
diff --git a/src/home/mqtt/_node.py b/src/home/mqtt/_node.py
index ddf5ba2..4e259a4 100644
--- a/src/home/mqtt/_node.py
+++ b/src/home/mqtt/_node.py
@@ -14,13 +14,17 @@ class MqttNode:
_modules: List[MqttModule]
_module_subscriptions: dict[str, MqttModule]
_node_id: str
+ _node_secret: str
_payload_callbacks: list[callable]
_wrapper: Optional[MqttWrapper]
- def __init__(self, node_id: str):
+ def __init__(self,
+ node_id: str,
+ node_secret: Optional[str] = None):
self._modules = []
self._module_subscriptions = {}
self._node_id = node_id
+ self._node_secret = node_secret
self._payload_callbacks = []
self._logger = logging.getLogger(self.__class__.__name__)
self._wrapper = None
@@ -42,7 +46,7 @@ class MqttNode:
payload = self._module_subscriptions[topic].handle_payload(self, topic, payload)
if isinstance(payload, MqttPayload):
for f in self._payload_callbacks:
- f(payload)
+ f(self, payload)
def load_module(self, module_name: str, *args, **kwargs) -> MqttModule:
module = importlib.import_module(f'..module.{module_name}', __name__)
@@ -78,3 +82,11 @@ class MqttNode:
@property
def id(self) -> str:
return self._node_id
+
+ @property
+ def secret(self) -> str:
+ return self._node_secret
+
+ @secret.setter
+ def secret(self, secret: str) -> None:
+ self._node_secret = secret
diff --git a/src/home/mqtt/_wrapper.py b/src/home/mqtt/_wrapper.py
index 41f9d89..0b32197 100644
--- a/src/home/mqtt/_wrapper.py
+++ b/src/home/mqtt/_wrapper.py
@@ -9,11 +9,15 @@ from ..util import strgen
class MqttWrapper(Mqtt):
_nodes: list[MqttNode]
- def __init__(self, topic_prefix='hk', randomize_client_id=False):
+ def __init__(self,
+ topic_prefix='hk',
+ randomize_client_id=False,
+ clean_session=True):
client_id = config['mqtt']['client_id']
if randomize_client_id:
client_id += '_'+strgen(6)
- super().__init__(clean_session=True, client_id=client_id)
+ super().__init__(clean_session=clean_session,
+ client_id=client_id)
self._nodes = []
self._topic_prefix = topic_prefix
diff --git a/src/home/mqtt/module/ota.py b/src/home/mqtt/module/ota.py
index e71cccc..70c5475 100644
--- a/src/home/mqtt/module/ota.py
+++ b/src/home/mqtt/module/ota.py
@@ -41,7 +41,7 @@ class OtaPayload(MqttPayload):
class MqttOtaModule(MqttModule):
- _ota_request: Optional[tuple[str, str, int]]
+ _ota_request: Optional[tuple[str, int]]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -52,9 +52,9 @@ class MqttOtaModule(MqttModule):
mqtt.subscribe_module("otares", self)
if self._ota_request is not None:
- secret, filename, qos = self._ota_request
+ filename, qos = self._ota_request
self._ota_request = None
- self.do_push_ota(secret, filename, qos)
+ self.do_push_ota(self._mqtt_node_ref.secret, filename, qos)
def handle_payload(self, mqtt: MqttNode, topic: str, payload: bytes) -> Optional[MqttPayload]:
if topic == 'otares':
@@ -69,10 +69,9 @@ class MqttOtaModule(MqttModule):
qos=qos)
def push_ota(self,
- secret: str,
filename: str,
qos: int):
if not self._initialized:
- self._ota_request = (secret, filename, qos)
+ self._ota_request = (filename, qos)
else:
- self.do_push_ota(secret, filename, qos)
+ self.do_push_ota(filename, qos)
diff --git a/src/home/mqtt/module/relay.py b/src/home/mqtt/module/relay.py
index ae88ddb..5383fb6 100644
--- a/src/home/mqtt/module/relay.py
+++ b/src/home/mqtt/module/relay.py
@@ -64,9 +64,9 @@ class MqttRelayModule(MqttModule):
mqtt.subscribe_module('relay/status', self)
def switchpower(self,
- enable: bool,
- secret: str):
- payload = MqttPowerSwitchPayload(secret=secret, state=enable)
+ enable: bool):
+ payload = MqttPowerSwitchPayload(secret=self._mqtt_node_ref.secret,
+ state=enable)
self._mqtt_node_ref.publish('relay/switch', payload=payload.pack())
def handle_payload(self, mqtt: MqttNode, topic: str, payload: bytes) -> Optional[MqttPayload]:
diff --git a/src/home/mqtt/module/temphum.py b/src/home/mqtt/module/temphum.py
index fe52523..0e22793 100644
--- a/src/home/mqtt/module/temphum.py
+++ b/src/home/mqtt/module/temphum.py
@@ -1,8 +1,8 @@
-from enum import auto
+# from enum import auto
from .._node import MqttNode
from .._module import MqttModule
from .._payload import MqttPayload
-from ...util import HashableEnum
+# from ...util import HashableEnum
from typing import Optional
from ...temphum import BaseSensor
@@ -24,30 +24,31 @@ class MqttTemphumDataPayload(MqttPayload):
error: int
-class MqttTempHumNodes(HashableEnum):
- KBN_SH_HALL = auto()
- KBN_SH_BATHROOM = auto()
- KBN_SH_LIVINGROOM = auto()
- KBN_SH_BEDROOM = auto()
-
- KBN_BH_2FL = auto()
- KBN_BH_2FL_STREET = auto()
- KBN_BH_1FL_LIVINGROOM = auto()
- KBN_BH_1FL_BEDROOM = auto()
- KBN_BH_1FL_BATHROOM = auto()
-
- KBN_NH_1FL_INV = auto()
- KBN_NH_1FL_CENTER = auto()
- KBN_NH_1LF_KT = auto()
- KBN_NH_1FL_DS = auto()
- KBN_NH_1FS_EZ = auto()
-
- SPB_FLAT120_CABINET = auto()
+# class MqttTempHumNodes(HashableEnum):
+# KBN_SH_HALL = auto()
+# KBN_SH_BATHROOM = auto()
+# KBN_SH_LIVINGROOM = auto()
+# KBN_SH_BEDROOM = auto()
+#
+# KBN_BH_2FL = auto()
+# KBN_BH_2FL_STREET = auto()
+# KBN_BH_1FL_LIVINGROOM = auto()
+# KBN_BH_1FL_BEDROOM = auto()
+# KBN_BH_1FL_BATHROOM = auto()
+#
+# KBN_NH_1FL_INV = auto()
+# KBN_NH_1FL_CENTER = auto()
+# KBN_NH_1LF_KT = auto()
+# KBN_NH_1FL_DS = auto()
+# KBN_NH_1FS_EZ = auto()
+#
+# SPB_FLAT120_CABINET = auto()
class MqttTempHumModule(MqttModule):
def __init__(self,
sensor: Optional[BaseSensor] = None,
+ write_to_database=False,
*args, **kwargs):
if sensor is not None:
kwargs['tick_interval'] = 10
diff --git a/src/inverter_bot.py b/src/inverter_bot.py
index fd5acf3..194263e 100755
--- a/src/inverter_bot.py
+++ b/src/inverter_bot.py
@@ -44,7 +44,7 @@ flags_map = {
}
logger = logging.getLogger(__name__)
-config.load('inverter_bot')
+config.load_app('inverter_bot')
bot.initialize()
bot.lang.ru(
diff --git a/src/inverter_mqtt_util.py b/src/inverter_mqtt_util.py
index edea29a..9db25dc 100755
--- a/src/inverter_mqtt_util.py
+++ b/src/inverter_mqtt_util.py
@@ -8,10 +8,10 @@ if __name__ == '__main__':
parser = ArgumentParser()
parser.add_argument('mode', type=str, choices=('sender', 'receiver'), nargs=1)
- config.load('inverter_mqtt_util', parser=parser)
+ config.load_app('inverter_mqtt_util', parser=parser)
arg = parser.parse_args()
- mqtt = MqttWrapper()
+ mqtt = MqttWrapper(clean_session=arg.mode[0] != 'receiver')
node = MqttNode(node_id='inverter')
module_kwargs = {}
if arg.mode[0] == 'sender':
diff --git a/src/ipcam_server.py b/src/ipcam_server.py
index 2c4915d..a54cd35 100755
--- a/src/ipcam_server.py
+++ b/src/ipcam_server.py
@@ -556,7 +556,7 @@ logger = logging.getLogger(__name__)
# --------------------
if __name__ == '__main__':
- config.load('ipcam_server')
+ config.load_app('ipcam_server')
open_database()
diff --git a/src/mqtt_node_util.py b/src/mqtt_node_util.py
index 0af430a..e5744b0 100755
--- a/src/mqtt_node_util.py
+++ b/src/mqtt_node_util.py
@@ -23,14 +23,14 @@ if __name__ == '__main__':
parser.add_argument('--node-secret', type=str,
help='node admin password')
- config.load('mqtt_util', parser=parser)
+ config.load_app('mqtt_util', parser=parser)
arg = parser.parse_args()
if (arg.switch_relay is not None or arg.node_secret is not None) and 'relay' not in arg.modules:
raise ArgumentError(None, '--relay is only allowed when \'relay\' module included in --modules')
mqtt = MqttWrapper(randomize_client_id=True)
- mqtt_node = MqttNode(node_id=arg.node_id)
+ mqtt_node = MqttNode(node_id=arg.node_id, node_secret=arg.node_secret)
mqtt.add_node(mqtt_node)
@@ -44,9 +44,7 @@ if __name__ == '__main__':
if m == 'relay' and arg.switch_relay is not None:
if not arg.node_secret:
raise ArgumentError(None, '--switch-relay requires --node-secret')
- module_instance.switchpower(mqtt_node,
- arg.switch_relay == 1,
- arg.node_secret)
+ module_instance.switchpower(arg.switch_relay == 1)
mqtt.configure_tls()
try:
@@ -58,7 +56,7 @@ if __name__ == '__main__':
if not arg.node_secret:
raise ArgumentError(None, 'pushing OTA requires --node-secret')
- ota_module.push_ota(arg.node_secret, arg.push_ota, 1)
+ ota_module.push_ota(arg.push_ota, 1)
while True:
sleep(0.1)
diff --git a/src/openwrt_log_analyzer.py b/src/openwrt_log_analyzer.py
index d31c3bf..35b755f 100755
--- a/src/openwrt_log_analyzer.py
+++ b/src/openwrt_log_analyzer.py
@@ -54,7 +54,7 @@ def main(mac: str,
if __name__ == '__main__':
- config.load('openwrt_log_analyzer')
+ config.load_app('openwrt_log_analyzer')
for ap in config['openwrt_log_analyzer']['aps']:
state_file = config['simple_state']['file']
state_file = state_file.replace('.txt', f'-{ap}.txt')
diff --git a/src/openwrt_logger.py b/src/openwrt_logger.py
index 3b19de2..97fe7a9 100755
--- a/src/openwrt_logger.py
+++ b/src/openwrt_logger.py
@@ -46,7 +46,7 @@ if __name__ == '__main__':
parser.add_argument('--access-point', type=int, required=True,
help='access point number')
- arg = config.load('openwrt_logger', parser=parser)
+ arg = config.load_app('openwrt_logger', parser=parser)
state = SimpleState(file=config['simple_state']['file'].replace('{ap}', str(arg.access_point)),
default={'seek': 0, 'size': 0})
diff --git a/src/polaris_kettle_bot.py b/src/polaris_kettle_bot.py
index 8438ab3..80baef3 100755
--- a/src/polaris_kettle_bot.py
+++ b/src/polaris_kettle_bot.py
@@ -41,7 +41,7 @@ from telegram.ext import (
)
logger = logging.getLogger(__name__)
-config.load('polaris_kettle_bot')
+config.load_app('polaris_kettle_bot')
primary_choices = (70, 80, 90, 100)
all_choices = range(
diff --git a/src/polaris_kettle_util.py b/src/polaris_kettle_util.py
index 816cff7..12c4388 100755
--- a/src/polaris_kettle_util.py
+++ b/src/polaris_kettle_util.py
@@ -75,7 +75,7 @@ def main():
parser.add_argument('-t', '--temperature', dest='temp', type=int, default=tempmax,
choices=range(tempmin, tempmax+tempstep, tempstep))
- arg = config.load('polaris_kettle_util', use_cli=True, parser=parser)
+ arg = config.load_app('polaris_kettle_util', use_cli=True, parser=parser)
if arg.mode == 'mqtt':
server = MqttServer()
diff --git a/src/pump_bot.py b/src/pump_bot.py
index ab73097..172108e 100755
--- a/src/pump_bot.py
+++ b/src/pump_bot.py
@@ -16,7 +16,7 @@ from home.mqtt.module.temphum import MqttTemphumDataPayload
from home.mqtt.module.diagnostics import InitialDiagnosticsPayload, DiagnosticsPayload
-config.load('pump_bot')
+config.load_app('pump_bot')
mqtt: Optional[MqttWrapper] = None
mqtt_node: Optional[MqttNode] = None
@@ -208,7 +208,7 @@ def markup(ctx: Optional[bot.Context]) -> Optional[ReplyKeyboardMarkup]:
return ReplyKeyboardMarkup(buttons, one_time_keyboard=False)
-def mqtt_payload_callback(payload: MqttPayload):
+def mqtt_payload_callback(mqtt_node: MqttNode, payload: MqttPayload):
global watering_mcu_status
types_the_node_can_send = (
diff --git a/src/pump_mqtt_bot.py b/src/pump_mqtt_bot.py
index 6a63caf..1c52b03 100755
--- a/src/pump_mqtt_bot.py
+++ b/src/pump_mqtt_bot.py
@@ -13,7 +13,7 @@ from home.mqtt.module.relay import MqttRelayState
from home.mqtt.module.diagnostics import InitialDiagnosticsPayload, DiagnosticsPayload
-config.load('pump_mqtt_bot')
+config.load_app('pump_mqtt_bot')
bot.initialize()
bot.lang.ru(
diff --git a/src/relay_mqtt_bot.py b/src/relay_mqtt_bot.py
index ebbff82..e7fa613 100755
--- a/src/relay_mqtt_bot.py
+++ b/src/relay_mqtt_bot.py
@@ -6,13 +6,12 @@ from functools import partial
from home.config import config
from home.telegram import bot
-from home.mqtt import MqttRelay, MqttRelayState
-from home.mqtt.esp import MqttEspDevice
-from home.mqtt.payload import MqttPayload
-from home.mqtt.payload.relay import InitialDiagnosticsPayload, DiagnosticsPayload
+from home.mqtt import MqttPayload, MqttNode, MqttWrapper
+from home.mqtt.module.relay import MqttRelayModule, MqttRelayState
+from home.mqtt.module.diagnostics import InitialDiagnosticsPayload, DiagnosticsPayload
-config.load('relay_mqtt_bot')
+config.load_app('relay_mqtt_bot')
bot.initialize()
bot.lang.ru(
@@ -34,7 +33,11 @@ status_emoji = {
'on': '✅',
'off': '❌'
}
-mqtt_relay: Optional[MqttRelay] = None
+
+
+# mqtt_relay: Optional[MqttRelayModule] = None
+mqtt: Optional[MqttWrapper] = None
+relay_nodes: dict[str, MqttRelayModule] = {}
relay_states: dict[str, MqttRelayState] = {}
@@ -43,23 +46,24 @@ class UserAction(Enum):
OFF = 'off'
-def on_mqtt_message(home_id, message: MqttPayload):
+def on_mqtt_message(node: MqttNode,
+ message: MqttPayload):
if isinstance(message, InitialDiagnosticsPayload) or isinstance(message, DiagnosticsPayload):
kwargs = dict(rssi=message.rssi, enabled=message.flags.state)
if isinstance(message, InitialDiagnosticsPayload):
kwargs['fw_version'] = message.fw_version
- if home_id not in relay_states:
- relay_states[home_id] = MqttRelayState()
- relay_states[home_id].update(**kwargs)
+ if node.id not in relay_states:
+ relay_states[node.id] = MqttRelayState()
+ relay_states[node.id].update(**kwargs)
-def enable_handler(home_id: str, ctx: bot.Context) -> None:
- mqtt_relay.set_power(home_id, True)
+def enable_handler(node_id: str, ctx: bot.Context) -> None:
+ relay_nodes[node_id].switchpower(True)
ctx.reply(ctx.lang('done'))
-def disable_handler(home_id: str, ctx: bot.Context) -> None:
- mqtt_relay.set_power(home_id, False)
+def disable_handler(node_id: str, ctx: bot.Context) -> None:
+ relay_nodes[node_id].switchpower(False)
ctx.reply(ctx.lang('done'))
@@ -86,9 +90,13 @@ def markup(ctx: Optional[bot.Context]) -> Optional[ReplyKeyboardMarkup]:
if __name__ == '__main__':
devices = []
+ mqtt = MqttWrapper()
for device_id, data in config['relays'].items():
- devices.append(MqttEspDevice(id=device_id,
- secret=data['secret']))
+ mqtt_node = MqttNode(node_id=device_id, node_secret=data['secret'])
+ relay_nodes[device_id] = mqtt_node.load_module('relay')
+ mqtt_node.add_payload_callback(on_mqtt_message)
+ mqtt.add_node(mqtt_node)
+
labels = data['labels']
bot.lang.ru(**{device_id: labels['ru']})
bot.lang.en(**{device_id: labels['en']})
@@ -101,12 +109,9 @@ if __name__ == '__main__':
messages.append(f'{type_emoji}{status_emoji[action.value]} {labels[_lang]}')
bot.handler(texts=messages)(partial(enable_handler if action == UserAction.ON else disable_handler, device_id))
- mqtt_relay = MqttRelay(devices=devices)
- mqtt_relay.set_message_callback(on_mqtt_message)
- mqtt_relay.configure_tls()
- mqtt_relay.connect_and_loop(loop_forever=False)
+ mqtt.configure_tls()
+ mqtt.connect_and_loop(loop_forever=False)
- # bot.enable_logging(BotType.RELAY_MQTT)
bot.run(start_handler=start)
- mqtt_relay.disconnect()
+ mqtt.disconnect()
diff --git a/src/relay_mqtt_http_proxy.py b/src/relay_mqtt_http_proxy.py
index 098facc..50a74a1 100755
--- a/src/relay_mqtt_http_proxy.py
+++ b/src/relay_mqtt_http_proxy.py
@@ -1,17 +1,19 @@
#!/usr/bin/env python3
from home import http
from home.config import config
-from home.mqtt import MqttRelay, MqttRelayState
-from home.mqtt.esp import MqttEspDevice
-from home.mqtt.payload import MqttPayload
-from home.mqtt.payload.relay import InitialDiagnosticsPayload, DiagnosticsPayload
-from typing import Optional
+from home.mqtt import MqttPayload, MqttWrapper, MqttNode, MqttModule
+from home.mqtt.module.relay import MqttRelayState, MqttRelayModule
+from home.mqtt.module.diagnostics import InitialDiagnosticsPayload, DiagnosticsPayload
+from typing import Optional, Union
-mqtt_relay: Optional[MqttRelay] = None
+mqtt: Optional[MqttWrapper] = None
+mqtt_nodes: dict[str, MqttNode] = {}
+relay_modules: dict[str, Union[MqttRelayModule, MqttModule]] = {}
relay_states: dict[str, MqttRelayState] = {}
-def on_mqtt_message(device_id, message: MqttPayload):
+def on_mqtt_message(node: MqttNode,
+ message: MqttPayload):
if isinstance(message, InitialDiagnosticsPayload) or isinstance(message, DiagnosticsPayload):
kwargs = dict(rssi=message.rssi, enabled=message.flags.state)
if device_id not in relay_states:
@@ -29,17 +31,22 @@ class RelayMqttHttpProxy(http.HTTPServer):
async def _relay_on_off(self,
enable: Optional[bool],
req: http.Request):
- device_id = req.match_info['id']
- device_secret = req.query['secret']
+ node_id = req.match_info['id']
+ node_secret = req.query['secret']
+
+ node = mqtt_nodes[node_id]
+ relay_module = relay_modules[node_id]
if enable is None:
- if device_id in relay_states and relay_states[device_id].ever_updated:
- cur_state = relay_states[device_id].enabled
+ if node_id in relay_states and relay_states[node_id].ever_updated:
+ cur_state = relay_states[node_id].enabled
else:
cur_state = False
enable = not cur_state
- mqtt_relay.set_power(device_id, enable, device_secret)
+ if not node.secret:
+ node.secret = node_secret
+ relay_module.switchpower(enable)
return self.ok()
async def relay_on(self, req: http.Request):
@@ -53,15 +60,22 @@ class RelayMqttHttpProxy(http.HTTPServer):
if __name__ == '__main__':
- config.load('relay_mqtt_http_proxy')
+ config.load_app('relay_mqtt_http_proxy')
+
+ mqtt = MqttWrapper()
+ for device_id, data in config['relays'].items():
+ mqtt_node = MqttNode(node_id=device_id)
+ relay_modules[device_id] = mqtt_node.load_module('relay')
+ mqtt_nodes[device_id] = mqtt_node
+ mqtt_node.add_payload_callback(on_mqtt_message)
+ mqtt.add_node(mqtt_node)
+ mqtt_node.add_payload_callback(on_mqtt_message)
- mqtt_relay = MqttRelay(devices=[MqttEspDevice(id=device_id) for device_id in config.get('relay.devices')])
- mqtt_relay.configure_tls()
- mqtt_relay.set_message_callback(on_mqtt_message)
- mqtt_relay.connect_and_loop(loop_forever=False)
+ mqtt.configure_tls()
+ mqtt.connect_and_loop(loop_forever=False)
proxy = RelayMqttHttpProxy(config.get_addr('server.listen'))
try:
proxy.run()
except KeyboardInterrupt:
- mqtt_relay.disconnect()
+ mqtt.disconnect()
diff --git a/src/sensors_bot.py b/src/sensors_bot.py
index dc081b0..152dd24 100755
--- a/src/sensors_bot.py
+++ b/src/sensors_bot.py
@@ -23,7 +23,7 @@ from home.api.types import (
TemperatureSensorLocation
)
-config.load('sensors_bot')
+config.load_app('sensors_bot')
bot.initialize()
bot.lang.ru(
diff --git a/src/sensors_mqtt_sender.py b/src/sensors_mqtt_sender.py
deleted file mode 100755
index 393962a..0000000
--- a/src/sensors_mqtt_sender.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python3
-import time
-import json
-
-from home.util import parse_addr, MySimpleSocketClient
-from home.mqtt import Mqtt, poll_tick
-from home.mqtt.payload.sensors import Temperature
-from home.config import config
-
-
-class MqttClient(Mqtt):
- def __init__(self):
- super().__init__(self)
- self._home_id = config['mqtt']['home_id']
-
- def poll(self):
- freq = int(config['mqtt']['sensors']['poll_freq'])
- self._logger.debug(f'freq={freq}')
-
- g = poll_tick(freq)
- while True:
- time.sleep(next(g))
- for k, v in config['mqtt']['sensors']['si7021'].items():
- host, port = parse_addr(v['addr'])
- self.publish_si7021(host, port, k)
-
- def publish_si7021(self, host: str, port: int, name: str):
- self._logger.debug(f"publish_si7021/{name}: {host}:{port}")
-
- try:
- now = time.time()
- socket = MySimpleSocketClient(host, port)
-
- socket.write('read')
- response = json.loads(socket.read().strip())
-
- temp = response['temp']
- humidity = response['humidity']
-
- self._logger.debug(f'publish_si7021/{name}: temp={temp} humidity={humidity}')
-
- pld = Temperature(time=round(now),
- temp=temp,
- rh=humidity)
- self._client.publish(f'hk/{self._home_id}/si7021/{name}',
- payload=pld.pack(),
- qos=1)
- except Exception as e:
- self._logger.exception(e)
-
-
-if __name__ == '__main__':
- config.load('sensors_mqtt_sender')
-
- client = MqttClient()
- client.configure_tls()
- client.connect_and_loop(loop_forever=False)
- client.poll()
diff --git a/src/sound_bot.py b/src/sound_bot.py
index 186337a..a2f8342 100755
--- a/src/sound_bot.py
+++ b/src/sound_bot.py
@@ -23,7 +23,7 @@ from telegram import ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardBu
from PIL import Image
-config.load('sound_bot')
+config.load_app('sound_bot')
nodes = {}
for nodename, nodecfg in config['nodes'].items():
diff --git a/src/sound_node.py b/src/sound_node.py
index 9d53362..b0b4a67 100755
--- a/src/sound_node.py
+++ b/src/sound_node.py
@@ -77,7 +77,7 @@ if __name__ == '__main__':
if not os.getegid() == 0:
raise RuntimeError("Must be run as root.")
- config.load('sound_node')
+ config.load_app('sound_node')
storage = SoundRecordStorage(config['node']['storage'])
diff --git a/src/sound_sensor_node.py b/src/sound_sensor_node.py
index d9a8999..e332174 100755
--- a/src/sound_sensor_node.py
+++ b/src/sound_sensor_node.py
@@ -14,7 +14,7 @@ if __name__ == '__main__':
if not os.getegid() == 0:
sys.exit('Must be run as root.')
- config.load('sound_sensor_node')
+ config.load_app('sound_sensor_node')
kwargs = {}
if 'delay' in config['node']:
diff --git a/src/sound_sensor_server.py b/src/sound_sensor_server.py
index aa62608..3a68a08 100755
--- a/src/sound_sensor_server.py
+++ b/src/sound_sensor_server.py
@@ -159,7 +159,7 @@ def api_error_handler(exc, name, req: RequestParams):
if __name__ == '__main__':
- config.load('sound_sensor_server')
+ config.load_app('sound_sensor_server')
hc = HitCounter()
api = WebAPIClient(timeout=(10, 60))
diff --git a/src/ssh_tunnels_config_util.py b/src/ssh_tunnels_config_util.py
index 3b2ba6e..03a8219 100755
--- a/src/ssh_tunnels_config_util.py
+++ b/src/ssh_tunnels_config_util.py
@@ -3,7 +3,7 @@
from home.config import config
if __name__ == '__main__':
- config.load('ssh_tunnels_config_util')
+ config.load_app('ssh_tunnels_config_util')
network_prefix = config['network']
hostnames = []
diff --git a/src/temphum_mqtt_node.py b/src/temphum_mqtt_node.py
index bcd72da..c3d1975 100755
--- a/src/temphum_mqtt_node.py
+++ b/src/temphum_mqtt_node.py
@@ -63,7 +63,7 @@ async def run_server(host, port):
if __name__ == '__main__':
- config.load()
+ config.load_app()
if 'measure_delay' in config['sensor']:
delay = float(config['sensor']['measure_delay'])
diff --git a/src/sensors_mqtt_receiver.py b/src/temphum_mqtt_receiver.py
index f7cb467..a4b888e 100755
--- a/src/sensors_mqtt_receiver.py
+++ b/src/temphum_mqtt_receiver.py
@@ -2,18 +2,8 @@
import paho.mqtt.client as mqtt
import re
-from home.mqtt import Mqtt
from home.config import config
-from home.mqtt.payload.sensors import Temperature
-from home.api.types import TemperatureSensorLocation
-from home.database import SensorsDatabase
-
-
-def get_sensor_type(sensor: str) -> TemperatureSensorLocation:
- for item in TemperatureSensorLocation:
- if sensor == item.name.lower():
- return item
- raise ValueError(f'unexpected sensor value: {sensor}')
+from home.mqtt import MqttWrapper, MqttNode
class MqttServer(Mqtt):
@@ -47,7 +37,12 @@ class MqttServer(Mqtt):
if __name__ == '__main__':
- config.load('sensors_mqtt_receiver')
+ config.load_app('temphum_mqtt_receiver')
+
+ mqtt = MqttWrapper(clean_session=False)
+ node = MqttNode(node_id='+')
+ node.load_module('temphum', write_to_database=True)
+ mqtt.add_node(node)
- server = MqttServer()
- server.connect_and_loop()
+ mqtt.configure_tls()
+ mqtt.connect_and_loop() \ No newline at end of file
diff --git a/src/temphumd.py b/src/temphumd.py
index bcd72da..c3d1975 100755
--- a/src/temphumd.py
+++ b/src/temphumd.py
@@ -63,7 +63,7 @@ async def run_server(host, port):
if __name__ == '__main__':
- config.load()
+ config.load_app()
if 'measure_delay' in config['sensor']:
delay = float(config['sensor']['measure_delay'])
diff --git a/src/test_new_config.py b/src/test_new_config.py
new file mode 100644
index 0000000..110e7a1
--- /dev/null
+++ b/src/test_new_config.py
@@ -0,0 +1,9 @@
+from home.config import config, app_config, LinuxBoardsConfig
+from pprint import pprint
+
+
+if __name__ == '__main__':
+ config.load_app(name=False)
+
+ lbc = LinuxBoardsConfig()
+ pprint(lbc.data) \ No newline at end of file
diff --git a/src/web_api.py b/src/web_api.py
index 0ddc6bd..0aa994a 100755
--- a/src/web_api.py
+++ b/src/web_api.py
@@ -231,7 +231,7 @@ if __name__ == '__main__':
_app_name = 'web_api'
if is_development_mode():
_app_name += '_dev'
- config.load(_app_name)
+ config.load_app(_app_name)
loop = asyncio.get_event_loop()
diff --git a/systemd/sensors_mqtt_receiver.service b/systemd/sensors_mqtt_receiver.service
index e67c112..5b9ff6a 100644
--- a/systemd/sensors_mqtt_receiver.service
+++ b/systemd/sensors_mqtt_receiver.service
@@ -1,12 +1,12 @@
[Unit]
-Description=sensors mqtt receiver
+Description=temphum mqtt receiver
After=network.target
[Service]
User=user
Group=user
Restart=on-failure
-ExecStart=python3 /home/user/home/src/sensors_mqtt_receiver.py
+ExecStart=python3 /home/user/home/src/temphum_mqtt_receiver.py
WorkingDirectory=/home/user
[Install]
diff --git a/systemd/sensors_mqtt_sender.service b/systemd/sensors_mqtt_sender.service
deleted file mode 100644
index a271d72..0000000
--- a/systemd/sensors_mqtt_sender.service
+++ /dev/null
@@ -1,13 +0,0 @@
-[Unit]
-Description=Sensors MQTT sender
-After=temphumd.service
-
-[Service]
-User=user
-Group=user
-Restart=on-failure
-ExecStart=/home/user/homekit/src/sensors_mqtt_sender.py
-WorkingDirectory=/home/user
-
-[Install]
-WantedBy=multi-user.target \ No newline at end of file
diff --git a/test/mqtt_relay_server_util.py b/test/mqtt_relay_server_util.py
index e6c5255..35bbf02 100755
--- a/test/mqtt_relay_server_util.py
+++ b/test/mqtt_relay_server_util.py
@@ -12,7 +12,7 @@ from src.home.mqtt.relay import MQTTRelayClient
if __name__ == '__main__':
- config.load('test_mqtt_relay_server')
+ config.load_app('test_mqtt_relay_server')
relay = MQTTRelayClient('test')
relay.configure_tls()
relay.connect_and_loop()
diff --git a/test/mqtt_relay_util.py b/test/mqtt_relay_util.py
index c1096cc..3634bbe 100755
--- a/test/mqtt_relay_util.py
+++ b/test/mqtt_relay_util.py
@@ -18,7 +18,7 @@ if __name__ == '__main__':
parser.add_argument('--off', action='store_true')
parser.add_argument('--stat', action='store_true')
- config.load('test_mqtt_relay', parser=parser)
+ config.load_app('test_mqtt_relay', parser=parser)
arg = parser.parse_args()
relay = MQTTRelayController('test')
diff --git a/test/test_amixer.py b/test/test_amixer.py
index c8bd546..464941e 100755
--- a/test/test_amixer.py
+++ b/test/test_amixer.py
@@ -28,7 +28,7 @@ if __name__ == '__main__':
parser.add_argument('--decr', type=str)
# parser.add_argument('--dump-config', action='store_true')
- args = config.load('test_amixer', parser=parser)
+ args = config.load_app('test_amixer', parser=parser)
# if args.dump_config:
# print(config.data)
diff --git a/test/test_api.py b/test/test_api.py
index 1f6361c..e80eb4c 100755
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -13,7 +13,7 @@ from src.home.config import config
if __name__ == '__main__':
- config.load('test_api')
+ config.load_app('test_api')
api = WebAPIClient()
print(api.log_bot_request(BotType.ADMIN, 1, "test_api.py"))
diff --git a/test/test_esp32_cam.py b/test/test_esp32_cam.py
index 27ce379..d743f09 100755
--- a/test/test_esp32_cam.py
+++ b/test/test_esp32_cam.py
@@ -21,7 +21,7 @@ if __name__ == '__main__':
parser.add_argument('--status', action='store_true',
help='print status and exit')
- arg = config.load(False, parser=parser)
+ arg = config.load_app(False, parser=parser)
cam = esp32.WebClient(addr=parse_addr(arg.addr))
if arg.status:
diff --git a/test/test_inverter_monitor.py b/test/test_inverter_monitor.py
index 3b1c6b0..621c0e9 100755
--- a/test/test_inverter_monitor.py
+++ b/test/test_inverter_monitor.py
@@ -372,5 +372,5 @@ def main():
if __name__ == '__main__':
- config.load('test_inverter_monitor')
+ config.load_app('test_inverter_monitor')
main()
diff --git a/test/test_ipcam_server_cleanup.py b/test/test_ipcam_server_cleanup.py
index b7eb23a..5f313a4 100644
--- a/test/test_ipcam_server_cleanup.py
+++ b/test/test_ipcam_server_cleanup.py
@@ -77,5 +77,5 @@ def cleanup_job():
if __name__ == '__main__':
- config.load('ipcam_server')
+ config.load_app('ipcam_server')
cleanup_job()
diff --git a/test/test_record_upload.py b/test/test_record_upload.py
index cbd3ca2..21e3d68 100755
--- a/test/test_record_upload.py
+++ b/test/test_record_upload.py
@@ -64,7 +64,7 @@ def api_success_handler(response, name, req: RequestParams):
if __name__ == '__main__':
- config.load('test_record_upload')
+ config.load_app('test_record_upload')
nodes = {}
for name, addr in config['nodes'].items():
diff --git a/test/test_sound_server_api.py b/test/test_sound_server_api.py
index e68c6f8..5295a5d 100755
--- a/test/test_sound_server_api.py
+++ b/test/test_sound_server_api.py
@@ -56,7 +56,7 @@ def hits_sender():
if __name__ == '__main__':
- config.load('test_api')
+ config.load_app('test_api')
hc = HitCounter()
api = WebAPIClient()
diff --git a/test/test_telegram_aio_send_photo.py b/test/test_telegram_aio_send_photo.py
index 705e534..4d05c03 100644
--- a/test/test_telegram_aio_send_photo.py
+++ b/test/test_telegram_aio_send_photo.py
@@ -20,7 +20,7 @@ async def main():
if __name__ == '__main__':
- config.load('test_telegram_aio_send_photo')
+ config.load_app('test_telegram_aio_send_photo')
loop = asyncio.get_event_loop()
asyncio.ensure_future(main())