From 6c97fd7327c6509ad7b7f962f20b1f75253960d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20S=C3=B6llner?= Date: Sun, 13 Aug 2023 21:41:45 +0200 Subject: [PATCH] moving to python3.9 and updating dependencies * simplifying Hafas endpoint (removing hafasglue daemon and using pyhafas) * updating versions for requests and Pillow * install now auto-builds binaries if downloadables incompatible with RPi * added some instructions about build dependencies to README * upgrading meross_iot from 0.4 to 0.3 due to breaking API changes * using meross_iot as pip package instead of as submodule --- README.md | 39 +++++++------ hafasglue.bash | 10 ---- hafasglue/.gitignore | 1 - hafasglue/hafasglue.js | 56 ------------------- hafasglue/package.json | 18 ------ hafasglued | 76 ------------------------- install-and-autorun.bash | 29 +++------- quietpaper.bash | 4 +- quietpaper/config.py | 11 +--- quietpaper/iot/meross.py | 62 ++++++++++++++++----- quietpaper/widgets/commute.py | 102 ++++++++++++++++------------------ quietpaper/widgets/laundry.py | 38 ++++--------- requirements.txt | 13 +++-- secret.template/_secrets.json | 6 -- 14 files changed, 147 insertions(+), 318 deletions(-) delete mode 100755 hafasglue.bash delete mode 100644 hafasglue/.gitignore delete mode 100644 hafasglue/hafasglue.js delete mode 100644 hafasglue/package.json delete mode 100644 hafasglued diff --git a/README.md b/README.md index cf71909..12ebdcf 100644 --- a/README.md +++ b/README.md @@ -18,23 +18,16 @@ The application is developed as Python application that can be run as a linux daemon and update the system at regular times (currently multiples of 5 minute steps which I found best for the slow refresh cycles of the Waveshare display). -The application also talks to a concurrently running NodeJs application -(called **hafasglue**) in order to interface with the German "Deutsche Bahn" public -transit API "Hafas". You can forego this concurrently running application and configure -the corresponding widget to retrieve data from the Google Directions API instead - which -is unfortunately not for free but (given that API calls are not cached) rather pricey. - Here are some other libraries and projects that were helpful and/or whose code I ended up incorporating into this project: * [`rgerganov/py-air-control`](https://github.com/rgerganov/py-air-control/) - Command Line App for controlling Philipps Air Purifier - modified version stored at `quietpaper/iot/airctrl.py` -* [`public-transport/hafas-client`](https://github.com/public-transport/hafas-client/blob/4/docs/journeys.md) - +* [`FahrplanDatenGarten/pyhafas`](https://github.com/FahrplanDatenGarten/pyhafas) - Hafas is the German "Deutsche Bahn" system that provides the electronic - public transit timetables and this is a NodeJs client of of their - rather clunky XML Webservice. The client is supplied as a much leaner - REST-API by my NodeJs servlet in `hafasglue`. + public transit timetables and this is a Python library for their + rather clunky XML Webservice. * [`momorientes/istheutefeinstaubalarm`](https://github.com/momorientes/istheutefeinstaubalarm) - my town Stuttgart, Germany provides "Smog Alerts" on which days we should leave our cars at home, use public transit for lower price (in some cases @@ -55,8 +48,9 @@ ended up incorporating into this project: 1. You need the following prequisites: * Raspbian Stretch Image -* Python 3 Installation -* Node Version Manager or Node Package Manager +* Python 3.9 Installation: + * [`albertogeniola/MerossIot`](https://github.com/albertogeniola/MerossIot) needs at least 3.7, but this caused Segmentation Faults on my Raspbian Stretch image whenever `asyncio` functionality was used + * Loosely follow these instructions and use an up-to-date Python 3.9.x patch version, e.gp. I used 3.9.17: https://gist.github.com/matthiasroos/3c8f1e0265eff6b60f6a7bcf701daa14) * Display connected to Raspberry 2. Next, if you want to use all widgets exactly in the layout I use you can just copy @@ -68,20 +62,25 @@ situation. re-arrange them. For this, see the next chapters. You might at least want to edit the file `quietpaper/config.py` which sets the layout of the widgets on the display. -4. You can then install both the `quietpaper` daemon (Python app which updates the display) -and the `hafasglue` daemon (Node-JS servlet which talks to Hafas in order to retrieve -public transit information) by calling: +4. Installing will build a few packages from their Python Wheels Sources. For this +process you need (once, you can uninstall those programs after the installation process): +```bash +sudo apt-get install libjpeg-dev zlib1g-dev # for installing pip Pillow from source +sudo apt-get install python-dev libatlas-base-dev # for installing Numpy from source ``` + +5. You can then install the `quietpaper` daemon (Python app which updates the display) +by calling: +```bash ./install-and-autorun.bash ``` -5. The display will now load! - You can start/stop/restart the daemons by calling -``` -sudo service {start|stop|restart} {quietpaper|hafasglue} +6. The display will now load! - You can start/stop/restart the daemons by calling +```bash +sudo service {start|stop|restart} quietpaper ``` ... or, after stopping the services, run them directly with: -``` -./hafasglue.bash +```bash ./quietpaper.bash ``` diff --git a/hafasglue.bash b/hafasglue.bash deleted file mode 100755 index eaf03c2..0000000 --- a/hafasglue.bash +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -l -here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -( - pushd $here >/dev/null 2>&1 - while true ; do - node ./hafasglue/hafasglue.js - done - exit $? - popd >/dev/null 2>&1 -) diff --git a/hafasglue/.gitignore b/hafasglue/.gitignore deleted file mode 100644 index 9e2c3c2..0000000 --- a/hafasglue/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hafasglue.js \ No newline at end of file diff --git a/hafasglue/hafasglue.js b/hafasglue/hafasglue.js deleted file mode 100644 index 5a6b293..0000000 --- a/hafasglue/hafasglue.js +++ /dev/null @@ -1,56 +0,0 @@ - -const express = require('express'); -const app = express(); -const hafas = require('hafas-client') -const hafasDb = require('hafas-client/p/db') -const hafasClient = hafas(hafasDb, 'hafas-quietpaper-glue') - -app.get('/', function(req, res) { - res.send('Hello World!'); -}); - -from = { - type: 'location', - address: '70565 Stuttgart', - latitude: 48.721010, - longitude: 9.094880 -} - -to = { - type: 'location', - address: 'Rothebühlplatz, Stuttgart', - latitude: 48.773630, - longitude: 9.169120 -} - -app.get('/query', function(req, res) { - from = { - type: 'location', - address: req.query.from_address, - latitude: req.query.from_latitude, - longitude: req.query.from_longitude - } - to = { - type: 'location', - address: req.query.to_address, - latitude: req.query.to_latitude, - longitude: req.query.to_longitude - } - opt = { - departure: (new Date(parseInt(req.query.departure)*1000)).toISOString(), - results: req.query.num_routes, - stopovers: false, - transfers: -1, - transferTime: 0, - accessibility: 'none', - language: 'en', - scheduledDays: false - } - response = hafasClient.journeys(from, to, opt) - .then((response) => (res.json(response.journeys))) - .catch((response) => (res.json(response.journeys))); -}); - -app.listen(3333, 'localhost', function () { - console.log('Started hafas-glue on to listen on localhost:3000.'); -}); \ No newline at end of file diff --git a/hafasglue/package.json b/hafasglue/package.json deleted file mode 100644 index 9269d29..0000000 --- a/hafasglue/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "hafasglue", - "version": "1.0.0", - "description": "", - "main": "hafasglue.js", - "dependencies": { - "express": "^4.17.1", - "hafas-client": "^4.6.1" - }, - "bin": { - "hafas-glue": "./hafasglue.js" - }, - "devDependencies": {}, - "scripts": {}, - "keywords": [], - "author": "", - "license": "ISC" -} diff --git a/hafasglued b/hafasglued deleted file mode 100644 index 2fd1a16..0000000 --- a/hafasglued +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh - -### BEGIN INIT INFO -# Provides: quietpaper -# Required-Start: $local_fs $network $syslog -# Required-Stop: $local_fs $network $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: quietpaper -# Description: quietpaper start-stop-daemon - Debian -### END INIT INFO - -NAME="hafasglue" -PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" -APPDIR="@APPDIR@" -APPBIN="@APPBIN@" -APPARGS="" -USER="quietpaper" -GROUP="quietpaper" - -# Include functions -set -e -. /lib/lsb/init-functions - -start() { - printf "Starting '$NAME'... " - start-stop-daemon --start --chuid "$USER:$GROUP" --background --make-pidfile --pidfile /var/run/$NAME.pid --chdir "$APPDIR" --exec "$APPBIN" -- $APPARGS || true - printf "done\n" -} - -#We need this function to ensure the whole process tree will be killed -killtree() { - local _pid=$1 - local _sig=${2-TERM} - for _child in $(ps -o pid --no-headers --ppid ${_pid}); do - killtree ${_child} ${_sig} - done - kill -${_sig} ${_pid} -} - -stop() { - printf "Stopping '$NAME'... " - [ -z `cat /var/run/$NAME.pid 2>/dev/null` ] || \ - while test -d /proc/$(cat /var/run/$NAME.pid); do - killtree $(cat /var/run/$NAME.pid) 15 - sleep 0.5 - done - [ -z `cat /var/run/$NAME.pid 2>/dev/null` ] || rm /var/run/$NAME.pid - printf "done\n" -} - -status() { - status_of_proc -p /var/run/$NAME.pid "" $NAME && exit 0 || exit $? -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop - start - ;; - status) - status - ;; - *) - echo "Usage: $NAME {start|stop|restart|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/install-and-autorun.bash b/install-and-autorun.bash index 3bf222b..05489f1 100755 --- a/install-and-autorun.bash +++ b/install-and-autorun.bash @@ -15,11 +15,13 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" fi # install venv - if [ ! -d ./venv-quietpaper ]; then - python3 -m virtualenv venv-quietpaper - . venv-quietpaper/bin/activate - pip3 install -r requirements.txt - pip3 install MerossIot/ + if [ ! -d ./venv3.9-quietpaper ]; then + python3.9 -m venv venv3.9-quietpaper + . venv3.9-quietpaper/bin/activate + pip install --upgrade "pip==23.2.1" + # I had problems installing Rust on Debian Stretch, so use an older version of + # cryptography that doesn't require it. + CRYPTOGRAPHY_DONT_BUILD_RUST=1 pip install -r requirements.txt deactivate fi @@ -42,23 +44,6 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" update-rc.d quietpaper defaults fi - # install dependencies for hafasglue - ( - pushd ./hafas-glue >/dev/null 2>&1 - npm install . - popd >/dev/null - ) - - # install hafasglue daemon - if [ ! -f /etc/init.d/hafasglue ]; then - cp ./hafasglued /etc/init.d/hafasglue - sed -i -e "s%@APPDIR@%$here%g" /etc/init.d/hafasglue - sed -i -e "s%@APPBIN@%$here/hafasglue.bash%g" /etc/init.d/hafasglue - chmod +x /etc/init.d/hafasglue - update-rc.d hafasglue defaults - fi - - service hafasglue start service quietpaper start popd >/dev/null 2>&1 diff --git a/quietpaper.bash b/quietpaper.bash index c3faada..62856a5 100755 --- a/quietpaper.bash +++ b/quietpaper.bash @@ -2,9 +2,9 @@ here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" ( pushd $here >/dev/null 2>&1 - source venv-quietpaper/bin/activate + source venv3.9-quietpaper/bin/activate while true ; do - PYTHONPATH=$here:$PYTHONPATH stdbuf -oL python3 quietpaper.py $@ + PYTHONPATH=$here:$PYTHONPATH stdbuf -oL python3.9 quietpaper.py $@ done exit $? popd >/dev/null 2>&1 diff --git a/quietpaper/config.py b/quietpaper/config.py index 73c6f23..7056831 100644 --- a/quietpaper/config.py +++ b/quietpaper/config.py @@ -10,7 +10,7 @@ ) from quietpaper.widgets.commute import ( CommuteWidget, - HafasCommuteStrategy + PyhafasCommuteStrategy ) from quietpaper.widgets.room import RoomWidget from quietpaper.widgets.smog import SmogWidget @@ -61,15 +61,10 @@ def secret(key, default=""): commute_y = 228 commute_hafas_glue = "http://localhost:3333/query" commute_from_address = secret("QP_COMMUTE_FROM_ADDRESS") -commute_from_latitude = secret("QP_COMMUTE_FROM_LATITUDE") -commute_from_longitude = secret("QP_COMMUTE_FROM_LONGITUDE") commute_to_address = secret("QP_COMMUTE_TO_ADDRESS") -commute_to_latitude = secret("QP_COMMUTE_TO_LATITUDE") -commute_to_longitude = secret("QP_COMMUTE_TO_LONGITUDE") commute_bus_stations = secret("QP_COMMUTE_BUS_STATIONS") commute_train_stations = secret("QP_COMMUTE_TRAIN_STATIONS") -commute_hafas = HafasCommuteStrategy(commute_hafas_glue, commute_from_address, commute_from_latitude, commute_from_longitude, - commute_to_address, commute_to_latitude, commute_to_longitude, commute_bus_stations, commute_train_stations) +commute_hafas = PyhafasCommuteStrategy(commute_from_address, commute_to_address, commute_bus_stations, commute_train_stations) commute = CommuteWidget(commute_hafas, commute_leave_for_bus, commute_leave_for_train, commute_x, commute_y) # Tado Connection @@ -152,7 +147,7 @@ def secret(key, default=""): secret("QP_LAUNDRY_DRYING_ACTIVE_POWER")) laundry_x = 186 laundry_y = 22 -laundry = LaundryWidget(laundry_x, laundry_y, washing_machine, drying_machine) +laundry = LaundryWidget(laundry_x, laundry_y, washing_machine, drying_machine, meross_connection) # MockScreen mock_png = "output/output.png" diff --git a/quietpaper/iot/meross.py b/quietpaper/iot/meross.py index 86ac1d9..49c2f7a 100755 --- a/quietpaper/iot/meross.py +++ b/quietpaper/iot/meross.py @@ -1,25 +1,57 @@ - -from meross_iot.cloud.devices.power_plugs import GenericPlug +import asyncio +from meross_iot.http_api import MerossHttpClient from meross_iot.manager import MerossManager +from quietpaper import logger class MerossConnection: + def __init__(self, meross_email, meross_password): self.manager = None self.meross_email = meross_email self.meross_password = meross_password - self.connect() + self.event_loop = asyncio.get_event_loop() + self.http_api_client = None + self.manager = None - def connect(self): - self.disconnect() - self.manager = MerossManager.from_email_and_password(self.meross_email, self.meross_password) - self.manager.start() + async def _async_disconnect(self): + try: + self.manager.close() + await self.http_api_client.async_logout() + except Exception as ee: + logger.warning("Error terminating Meross Connection: " + (ee.message if hasattr(ee, 'message') else type(ee).__name__)) + self.manager = None + self.http_api_client = None - def disconnect(self): - if self.manager is not None: - self.manager.stop() + async def _async_connect(self): + try: + self.http_api_client = await MerossHttpClient.async_from_user_password(email=self.meross_email, password=self.meross_password) + self.manager = MerossManager(http_client=self.http_api_client) + await self.manager.async_init() + await self.manager.async_device_discovery() + except Exception as ee: + logger.warning("Error initializing Meross Connection: " + (ee.message if hasattr(ee, 'message') else type(ee).__name__)) + self.http_api_client = None + self.manager = None + + async def _async_get_power_of_plug(self, plug_name): + if self.manager is None or self.http_api_client is None: + await self._async_disconnect() + await self._async_connect() + try: + plugs = self.manager.find_devices(device_name=plug_name) + await plugs[0].async_update() + return (await plugs[0].async_get_instant_metrics()).power + except Exception as ee: + logger.warning("Error querying power of plug '" + plug_name + "'. Resetting connection to Meross. " + (ee.message if hasattr(ee, 'message') else type(ee).__name__)) + plugs = [] + await self._async_disconnect() + await self._async_connect() + + def connect(self): + self.event_loop.run_until_complete(self._async_connect()) - def get_plug_by_name(self, name): - for p in self.manager.get_devices_by_kind(GenericPlug): - if p.name == name: - return p - return None \ No newline at end of file + def disconnect(self): + self.event_loop.run_until_complete(self._async_disconnect()) + + def get_power_of_plug(self, plug_name): + return self.event_loop.run_until_complete(self._async_get_power_of_plug(plug_name)) diff --git a/quietpaper/widgets/commute.py b/quietpaper/widgets/commute.py index 4f6dfca..77a4bd7 100644 --- a/quietpaper/widgets/commute.py +++ b/quietpaper/widgets/commute.py @@ -2,75 +2,71 @@ import json import datetime import dateutil.parser -import pprint import itertools from quietpaper import logger -import urllib.request, urllib.parse -import json from dateutil import tz from PIL import ImageFont - +from pyhafas.profile import DBProfile +from pyhafas import HafasClient +from pyhafas.types.fptf import Mode QP_COMMUTE_NUM_ROUTES = 3 QP_COMMUTE_SMALL_FONT = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 12) -class HafasCommuteStrategy: +class PyhafasCommuteStrategy: - def __init__(self, hafas_glue_url, from_address, from_latitude, from_longitude, to_address, to_latitude, to_longitude, - bus_stations={}, train_stations={}): - self.hafas_glue_service = hafas_glue_url - self.from_latitude = from_latitude - self.to_latitude = to_latitude - self.from_address = from_address - self.to_address = to_address - self.from_longitude = from_longitude - self.to_longitude = to_longitude - self.bus_stations = bus_stations - self.train_stations = train_stations + def __init__(self, from_loc, to_loc, bus_stations, train_stations): + try: + self.hafas_client = HafasClient(DBProfile()) + self.from_location = self.hafas_client.locations(from_loc)[0] + self.to_location = self.hafas_client.locations(to_loc)[0] + self.bus_stations = bus_stations + self.train_stations = train_stations + except Exception as e: + logger.warning("Cannot initialize PyhafasCommuteStrategy: " + (e.message if hasattr(e, 'message') else type(e).__name__)) def initialize(self, commute_widget): pass - def _parse_route(self, route): - arrival = None - arrival_delay = None - result = {"bus": None, "train": None, "city": None, "bus_station": None, "train_station": None} - for leg in route["legs"]: - is_bus = "line" in leg and leg["line"]["mode"] == "bus" - is_train = "line" in leg and leg["line"]["mode"] == "train" - departure = dateutil.parser.parse(leg["departure"]) - if is_bus and result["bus"] is None: - result["bus"] = departure - result["bus_station"] = self.bus_stations.get(leg["origin"]["name"], "*") - if result["bus_station"] == "*": - logger.warning("Unknown bus station found: %s" % leg["origin"]["name"]) - result["bus_delay"] = int(leg["departureDelay"])/60 if "departureDelay" in leg else 0 - elif is_train and result["train"] is None: - result["train"] = departure - result["train_station"] = self.train_stations.get(leg["origin"]["name"], "*") - if result["train_station"] == "*": - logger.warning("Unknown train station found: %s" % leg["origin"]["name"]) - result["train_delay"] = int(leg["departureDelay"])/60 if "departureDelay" in leg else 0 - arrival = dateutil.parser.parse(leg["arrival"]) - arrival_delay = int(leg["arrivalDelay"])/60 if "arrivalDelay" in leg else 0 - if result["train"] is not None: - result["city"] = arrival - result["city_delay"] = arrival_delay - return result - def retrieve(self, commute_widget): try: - start = datetime.datetime.now() - vals = [self.from_address, self.from_latitude, self.from_longitude, self.to_address, self.to_latitude, self.to_longitude, str(int(start.timestamp())), str(commute_widget.num_routes)] - args = [urllib.parse.quote(val.encode('utf-8')) for val in vals] - suffix = "?from_address={}&from_latitude={}&from_longitude={}&to_address={}&to_latitude={}&to_longitude={}&departure={}&num_routes={}" - hafas_url = self.hafas_glue_service + suffix.format(*args) - with urllib.request.urlopen(hafas_url) as hafas_call: - commute_widget.data = json.loads(hafas_call.read().decode()) - routes = [self._parse_route(route) for route in commute_widget.data] - commute_widget.routes = [route for route in routes if route["city"] is not None] + journeys = self.hafas_client.journeys( + origin=self.from_location, + destination=self.to_location, + date=datetime.datetime.now() + ) + routes = [] + for journey in journeys[:(3 if len(journeys) > 3 else len(journeys))]: + route = { + "bus": None, + "bus_station": None, + "bus_delay": None, + "train": None, + "train_station": None, + "train_delay": None, + "city": None, + "city_delay": None + } + for leg in journey.legs: + if route["bus"] is None and route["train"] is None and (leg.mode == Mode.BUS or leg.name.startswith("Bus")): + route["bus"] = leg.departure + route["bus_delay"] = leg.departureDelay.total_seconds()/60 if leg.departureDelay is not None else 0 + route["bus_station"] = self.bus_stations.get(leg.origin.name, "*") + if route["bus_station"] == "*": + logger.warning("Unknown bus station found: %s" % leg.origin.name) + elif route["train"] is None and (leg.mode == Mode.TRAIN): + route["train"] = leg.departure + route["train_delay"] = leg.departureDelay.total_seconds()/60 if leg.departureDelay is not None else 0 + route["train_station"] = self.train_stations.get(leg.origin.name, "*") + if route["train_station"] == "*": + logger.warning("Unknown train station found: %s" % leg.origin.name) + route["city"] = leg.arrival + route["city_delay"] = leg.arrivalDelay.total_seconds()/60 if leg.arrivalDelay is not None else 0 + routes.append(route) + commute_widget.data = journeys + commute_widget.routes = routes except Exception as e: - logger.warning("Cannot retrieve HafasCommuteStrategy: " + (e.message if hasattr(e, 'message') else type(e).__name__)) + logger.warning("Cannot retrieve PyhafasCommuteStrategy: " + (e.message if hasattr(e, 'message') else type(e).__name__)) class GoogleCommuteStrategy: diff --git a/quietpaper/widgets/laundry.py b/quietpaper/widgets/laundry.py index c3975dd..95104c1 100644 --- a/quietpaper/widgets/laundry.py +++ b/quietpaper/widgets/laundry.py @@ -2,28 +2,16 @@ from quietpaper import logger class LaundryMachine: - def __init__(self, name, meross_connection, stby_power, active_power): - self.name = name - self.connection = meross_connection + def __init__(self, plug_name, meross_connection, stby_power, active_power): + self.plug_name = plug_name + self.meross_connection = meross_connection self.stby_power = stby_power self.active_power = active_power self.last_active = None - def get_power(self): - self.connection.connect() - plug = self.connection.get_plug_by_name(self.name) - if plug is not None: - electricity = plug.get_electricity() - if electricity and "power" in electricity and "config" in electricity: - return electricity["power"] / electricity["config"]["electricityRatio"] - else: - return None - else: - return None - self.connection.disconnect() - def get_state(self): - power = self.get_power() + power = self.meross_connection.get_power_of_plug(self.plug_name) + logger.info("Power of " + self.plug_name + " is " + str(power)) if (power is not None and power > self.stby_power): if power > self.active_power: self.last_active = datetime.datetime.now() @@ -44,27 +32,23 @@ def get_state(self): class LaundryWidget: - def __init__(self, x, y, washing_machine, drying_machine): + def __init__(self, x, y, washing_machine, drying_machine, meross_connection): self.x = x self.y = y self.washing_machine = washing_machine self.washing_state = None self.drying_machine = drying_machine self.drying_state = None + self.meross_connection = meross_connection def initialize(self): pass def retrieve(self, cycle): - try: - self.washing_state = self.washing_machine.get_state() - except Exception as ee: - logger.warning("Cannot retrieve LaundryWidget.washing_state: " + (ee.message if hasattr(ee, 'message') else type(ee).__name__)) - try: - self.drying_state = self.drying_machine.get_state() - except Exception as ee: - logger.warning("Cannot retrieve LaundryWidget.drying_state: " + (ee.message if hasattr(ee, 'message') else type(ee).__name__)) - + self.meross_connection.connect() + self.washing_state = self.washing_machine.get_state() + self.drying_state = self.drying_machine.get_state() + self.meross_connection.disconnect() def get_retrieve_rate(self, cycle): return 2 diff --git a/requirements.txt b/requirements.txt index 98ae5a3..7c3c118 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,16 @@ # for widgets.office gspread==3.1.0 oauth2client==4.1.3 +cryptography==3.4.8 # allows to set CRYPTOGRAPHY_DONT_BUILD_RUST=1, possible until v3.5, PyOpenSSL requires only >=2.3 PyOpenSSL==19.0.0 python-dateutil==2.8.1 # for widgets.commute googlemaps==3.1.3 +pyhafas==0.4.0 # for widgets.room -requests==2.22.0 +requests==2.31.0 # for widgets.smog bs4==0.0.1 @@ -22,10 +24,13 @@ google-api-python-client==1.7.11 google-auth-httplib2==0.0.3 google-auth-oauthlib==0.4.1 +# for widgets.laundry +meross_iot==0.4.5.9 + # for epd* and display # note: compiling Pillow from source needs "sudo apt-get install libjpeg-dev zlib1g-dev" -Pillow>=6.2.2 +Pillow==7.2.0 --no-binary Pillow RPi.GPIO==0.6.5 spidev==3.4 -# note: Numpy needs sudo apt-get install python-dev libatlas-base-dev -numpy==1.17.3 \ No newline at end of file +# note: compiling numpy from source needs "sudo apt-get install python-dev libatlas-base-dev" +numpy==1.22.0 --no-binary numpy \ No newline at end of file diff --git a/secret.template/_secrets.json b/secret.template/_secrets.json index af77c19..3c61c6f 100644 --- a/secret.template/_secrets.json +++ b/secret.template/_secrets.json @@ -11,13 +11,7 @@ "QP_MONITOR_VPN_HOST": "", "QP_MONITOR_NAS_HOST": "", "QP_COMMUTE_FROM_ADDRESS": "", - "QP_COMMUTE_FROM_LATITUDE": "", - "QP_COMMUTE_FROM_LONGITUDE": "", "QP_COMMUTE_TO_ADDRESS": "", - "QP_COMMUTE_TO_LATITUDE": "", - "QP_COMMUTE_TO_LONGITUDE": "", - "QP_COMMUTE_BUS_PREFERRED_STATION": "", - "QP_COMMUTE_TRAIN_PREFERRED_STATION": "", "QP_COMMUTE_BUS_STATIONS": { "": "a", "": "b",