Move to python logging
This commit is contained in:
parent
5524d16f68
commit
d38abe28ba
5 changed files with 95 additions and 62 deletions
|
@ -2,13 +2,17 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
from logging import getLogger
|
||||||
|
from logging.config import dictConfig as loggingDictConfig
|
||||||
|
|
||||||
from bluepy.btle import BTLEDisconnectError # type: ignore
|
from bluepy.btle import BTLEDisconnectError # type: ignore
|
||||||
from serial import SerialException # type: ignore
|
from serial import SerialException # type: ignore
|
||||||
|
|
||||||
from .config import get_config, get_consumers, get_interface
|
from .config import get_config, get_consumers, get_interface
|
||||||
from .protocol import ChargeController
|
from .protocol import ChargeController
|
||||||
from .util import Periodical, log
|
from .util import Periodical
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CommunicationError(BTLEDisconnectError, SerialException, IOError):
|
class CommunicationError(BTLEDisconnectError, SerialException, IOError):
|
||||||
|
@ -17,25 +21,24 @@ class CommunicationError(BTLEDisconnectError, SerialException, IOError):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
conf = get_config()
|
conf = get_config()
|
||||||
|
|
||||||
|
loggingDictConfig(conf.get("logging", {}))
|
||||||
consumers = get_consumers(conf)
|
consumers = get_consumers(conf)
|
||||||
|
|
||||||
per_voltages = Periodical(interval=15)
|
per_voltages = Periodical(interval=15)
|
||||||
per_current_hist = Periodical(interval=60)
|
per_current_hist = Periodical(interval=60)
|
||||||
# import serial
|
|
||||||
|
|
||||||
# ser = serial.Serial()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
log("Connecting...")
|
logger.info("Connecting...")
|
||||||
with get_interface() as dev:
|
with get_interface() as dev:
|
||||||
log("Connected.")
|
logger.info("Connected.")
|
||||||
|
|
||||||
cc = ChargeController(dev)
|
cc = ChargeController(dev)
|
||||||
log(f"Controller model: {cc.model}")
|
logger.info(f"Controller model: {cc.model}")
|
||||||
log(f"Controller version: {cc.version}")
|
logger.info(f"Controller version: {cc.version}")
|
||||||
log(f"Controller serial: {cc.serial}")
|
logger.info(f"Controller serial: {cc.serial}")
|
||||||
for consumer in consumers:
|
for consumer in consumers:
|
||||||
consumer.controller = cc
|
consumer.controller = cc
|
||||||
|
|
||||||
|
@ -59,7 +62,7 @@ def main():
|
||||||
for i in range(min(days, 4)):
|
for i in range(min(days, 4)):
|
||||||
hist = cc.get_historical(i)
|
hist = cc.get_historical(i)
|
||||||
res = hist.as_dict()
|
res = hist.as_dict()
|
||||||
log({i: res})
|
logger.debug({i: res})
|
||||||
for consumer in consumers:
|
for consumer in consumers:
|
||||||
consumer.write({str(i): res})
|
consumer.write({str(i): res})
|
||||||
|
|
||||||
|
@ -68,14 +71,14 @@ def main():
|
||||||
|
|
||||||
if per_voltages(now):
|
if per_voltages(now):
|
||||||
data = cc.state.as_dict()
|
data = cc.state.as_dict()
|
||||||
log(data)
|
logger.debug(data)
|
||||||
for consumer in consumers:
|
for consumer in consumers:
|
||||||
consumer.write(data)
|
consumer.write(data)
|
||||||
|
|
||||||
if per_current_hist(now):
|
if per_current_hist(now):
|
||||||
data = cc.today.as_dict()
|
data = cc.today.as_dict()
|
||||||
data.update(cc.extra.as_dict())
|
data.update(cc.extra.as_dict())
|
||||||
log(data)
|
logger.debug(data)
|
||||||
for consumer in consumers:
|
for consumer in consumers:
|
||||||
consumer.write(data)
|
consumer.write(data)
|
||||||
|
|
||||||
|
@ -91,7 +94,7 @@ def main():
|
||||||
# write(wd, CMD_ENABLE_LOAD)
|
# write(wd, CMD_ENABLE_LOAD)
|
||||||
|
|
||||||
except CommunicationError:
|
except CommunicationError:
|
||||||
log("ERROR: Disconnected")
|
logger.error("Disconnected")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
except (KeyboardInterrupt, SystemExit, Exception) as e:
|
except (KeyboardInterrupt, SystemExit, Exception) as e:
|
||||||
|
|
|
@ -27,6 +27,29 @@ def get_config() -> Dict[str, Any]:
|
||||||
with open("config.yaml", "r") as fh:
|
with open("config.yaml", "r") as fh:
|
||||||
conf: dict = yaml.safe_load(fh)
|
conf: dict = yaml.safe_load(fh)
|
||||||
conf.setdefault("consumers", {})
|
conf.setdefault("consumers", {})
|
||||||
|
logging = conf.setdefault("logging", {})
|
||||||
|
logging.setdefault("version", 1)
|
||||||
|
logging.setdefault("disable_existing_loggers", False)
|
||||||
|
logging.setdefault(
|
||||||
|
"handlers",
|
||||||
|
{
|
||||||
|
"console": {
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"formatter": "default",
|
||||||
|
"level": "INFO",
|
||||||
|
"stream": "ext://sys.stdout",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
logging.setdefault(
|
||||||
|
"formatters",
|
||||||
|
{
|
||||||
|
"format": "%(asctime)s %(levelname)-8s %(name)-15s %(message)s",
|
||||||
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
loggers = logging.setdefault("loggers", {})
|
||||||
|
loggers.setdefault("root", {"handlers": ["console"], "level": "DEBUG"})
|
||||||
|
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
|
@ -34,7 +57,9 @@ def get_config() -> Dict[str, Any]:
|
||||||
def write_config(conf: Dict[str, Any]):
|
def write_config(conf: Dict[str, Any]):
|
||||||
with open(".config.yaml~writing", "w") as fh:
|
with open(".config.yaml~writing", "w") as fh:
|
||||||
yaml.safe_dump(conf, fh, indent=2, encoding="utf-8")
|
yaml.safe_dump(conf, fh, indent=2, encoding="utf-8")
|
||||||
os.rename(".config.yaml~writing", "config.yaml")
|
fh.flush()
|
||||||
|
os.fsync(fh.fileno())
|
||||||
|
os.replace(".config.yaml~writing", "config.yaml")
|
||||||
|
|
||||||
|
|
||||||
def get_consumers(conf: Optional[Dict[str, Any]] = None) -> List[BaseConsumer]:
|
def get_consumers(conf: Optional[Dict[str, Any]] = None) -> List[BaseConsumer]:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import json
|
import json
|
||||||
|
from logging import getLogger
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from typing import Any, Dict, List, Optional, TypeAlias
|
from typing import Any, Dict, List, Optional, TypeAlias
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
@ -9,6 +10,8 @@ import paho.mqtt.client as mqtt
|
||||||
from ..solar_types import DataName
|
from ..solar_types import DataName
|
||||||
from . import BaseConsumer
|
from . import BaseConsumer
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
MAP_VALUES: Dict[DataName, Dict[str, Any]] = {
|
MAP_VALUES: Dict[DataName, Dict[str, Any]] = {
|
||||||
# DataName.BATTERY_VOLTAGE_MIN: {},
|
# DataName.BATTERY_VOLTAGE_MIN: {},
|
||||||
# DataName.BATTERY_VOLTAGE_MAX: {},
|
# DataName.BATTERY_VOLTAGE_MAX: {},
|
||||||
|
@ -161,8 +164,11 @@ class MqttConsumer(BaseConsumer):
|
||||||
elif err.errno == -3:
|
elif err.errno == -3:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
logger.exception("Unknown error connecting to mqtt server")
|
||||||
raise
|
raise
|
||||||
print(err)
|
logger.warning(
|
||||||
|
"Temporary failure connecting to mqtt server", exc_info=True
|
||||||
|
)
|
||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
return self._client
|
return self._client
|
||||||
|
|
||||||
|
@ -245,7 +251,7 @@ class MqttConsumer(BaseConsumer):
|
||||||
# The callback for when the client receives a CONNACK response from the server.
|
# The callback for when the client receives a CONNACK response from the server.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def on_connect(client: mqtt.Client, userdata: "MqttConsumer", flags, rc):
|
def on_connect(client: mqtt.Client, userdata: "MqttConsumer", flags, rc):
|
||||||
print("Connected with result code " + str(rc))
|
logger.info("MQTT connected with result code %s", rc)
|
||||||
|
|
||||||
# Subscribing in on_connect() means that if we lose the connection and
|
# Subscribing in on_connect() means that if we lose the connection and
|
||||||
# reconnect then subscriptions will be renewed.
|
# reconnect then subscriptions will be renewed.
|
||||||
|
@ -263,10 +269,7 @@ class MqttConsumer(BaseConsumer):
|
||||||
client: mqtt.Client, userdata: "MqttConsumer", message: mqtt.MQTTMessage
|
client: mqtt.Client, userdata: "MqttConsumer", message: mqtt.MQTTMessage
|
||||||
):
|
):
|
||||||
assert userdata.controller is not None
|
assert userdata.controller is not None
|
||||||
print(message)
|
logger.debug(message.payload)
|
||||||
print(message.info)
|
|
||||||
print(message.state)
|
|
||||||
print(message.payload)
|
|
||||||
payload = message.payload.decode().upper() in ("ON", "TRUE", "ENABLE", "YES")
|
payload = message.payload.decode().upper() in ("ON", "TRUE", "ENABLE", "YES")
|
||||||
|
|
||||||
res = userdata.controller.load_enabled = payload
|
res = userdata.controller.load_enabled = payload
|
||||||
|
@ -276,29 +279,29 @@ class MqttConsumer(BaseConsumer):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def on_connect_fail(client: mqtt.Client, userdata: "MqttConsumer"):
|
def on_connect_fail(client: mqtt.Client, userdata: "MqttConsumer"):
|
||||||
print(userdata.__class__.__name__, "on_connect_fail")
|
logger.warning("on_connect_fail")
|
||||||
|
|
||||||
# The callback for when a PUBLISH message is received from the server.
|
# The callback for when a PUBLISH message is received from the server.
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def on_message(client, userdata, msg):
|
def on_message(client, userdata, msg):
|
||||||
print(msg.topic + " " + str(msg.payload))
|
logger.info(msg.topic + " " + str(msg.payload))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def on_disconnect(client: mqtt.Client, userdata: "MqttConsumer", rc, prop=None):
|
def on_disconnect(client: mqtt.Client, userdata: "MqttConsumer", rc, prop=None):
|
||||||
print(userdata.__class__.__name__, "on_disconnect", rc)
|
logger.warning("on_disconnect %s", rc)
|
||||||
|
|
||||||
def poll(self):
|
def poll(self):
|
||||||
res = self.client.loop(timeout=0.1, max_packets=5)
|
res = self.client.loop(timeout=0.1, max_packets=5)
|
||||||
|
|
||||||
if res != mqtt.MQTT_ERR_SUCCESS:
|
if res != mqtt.MQTT_ERR_SUCCESS:
|
||||||
print(self.__class__.__name__, "loop returned non-success:", res)
|
logger.warning("loop returned non-success: %s", res)
|
||||||
try:
|
try:
|
||||||
sleep(1)
|
sleep(1)
|
||||||
res = self.client.reconnect()
|
res = self.client.reconnect()
|
||||||
if res != mqtt.MQTT_ERR_SUCCESS:
|
if res != mqtt.MQTT_ERR_SUCCESS:
|
||||||
print(self.__class__.__name__, "Reconnect failed:", res)
|
logger.error("Reconnect failed: %s", res)
|
||||||
except (OSError, mqtt.WebsocketConnectionError) as err:
|
except (OSError, mqtt.WebsocketConnectionError) as err:
|
||||||
print(self.__class__.__name__, "Reconnect failed:", err)
|
logger.error("Reconnect failed: %s", err)
|
||||||
|
|
||||||
return super().poll()
|
return super().poll()
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import struct
|
import struct
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
from typing import Callable, Collection, Optional
|
from logging import getLogger
|
||||||
|
from typing import Callable, Collection, List, Optional
|
||||||
|
|
||||||
from libscrc import modbus # type: ignore
|
from libscrc import modbus # type: ignore
|
||||||
|
|
||||||
|
@ -16,7 +16,8 @@ from .solar_types import (
|
||||||
HistoricalData,
|
HistoricalData,
|
||||||
HistoricalExtraInfo,
|
HistoricalExtraInfo,
|
||||||
)
|
)
|
||||||
from .util import log
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def write(fh, data):
|
def write(fh, data):
|
||||||
|
@ -92,15 +93,13 @@ def discardUntil(fh: BaseInterface, byte: int, timeout=10) -> Optional[int]:
|
||||||
return b[0]
|
return b[0]
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
discarded = 0
|
discarded: List[str] = []
|
||||||
read_byte = expand(fh.read(1))
|
read_byte = expand(fh.read(1))
|
||||||
while read_byte != byte:
|
while read_byte != byte:
|
||||||
if read_byte is not None:
|
if read_byte is not None:
|
||||||
if not discarded:
|
if not discarded:
|
||||||
log("Discarding", end="")
|
discarded.append("Discarding")
|
||||||
discarded += 1
|
discarded.append(f"{read_byte:02X}")
|
||||||
print(f" {read_byte:02X}", end="")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
if time.time() - start > timeout:
|
if time.time() - start > timeout:
|
||||||
read_byte = None
|
read_byte = None
|
||||||
|
@ -109,8 +108,7 @@ def discardUntil(fh: BaseInterface, byte: int, timeout=10) -> Optional[int]:
|
||||||
read_byte = expand(fh.read(1))
|
read_byte = expand(fh.read(1))
|
||||||
|
|
||||||
if discarded:
|
if discarded:
|
||||||
print()
|
logger.debug(" ".join(discarded))
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
return read_byte
|
return read_byte
|
||||||
|
|
||||||
|
@ -134,14 +132,18 @@ def readMemory(fh: BaseInterface, address: int, words: int = 1) -> Optional[byte
|
||||||
try:
|
try:
|
||||||
crc = struct.unpack_from("<H", _crc)[0]
|
crc = struct.unpack_from("<H", _crc)[0]
|
||||||
except struct.error:
|
except struct.error:
|
||||||
log(f"readMemory: CRC error; read {len(_crc)} bytes (2 expected)")
|
logger.error(
|
||||||
|
"readMemory: CRC error; read %s bytes (2 expected)", len(_crc)
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
calculated_crc = modbus(bytes([tag, operation, size, *data]))
|
calculated_crc = modbus(bytes([tag, operation, size, *data]))
|
||||||
if crc == calculated_crc:
|
if crc == calculated_crc:
|
||||||
return data
|
return data
|
||||||
else:
|
else:
|
||||||
log(f"readMemory: CRC error; {crc:04X} != {calculated_crc:04X}")
|
logger.error(
|
||||||
log("data or crc is falsely", header, data, _crc)
|
f"readMemory: CRC error; {crc:04X} != {calculated_crc:04X}"
|
||||||
|
)
|
||||||
|
logger.error("data or crc is falsely %s %s %s", header, data, _crc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,7 +168,7 @@ def writeMemory(fh: BaseInterface, address: int, data: bytes):
|
||||||
header = fh.read(3)
|
header = fh.read(3)
|
||||||
if header and len(header) == 3:
|
if header and len(header) == 3:
|
||||||
operation, size, address = header
|
operation, size, address = header
|
||||||
log(header)
|
logger.log(5, header)
|
||||||
# size field is zero when writing device name for whatever reason
|
# size field is zero when writing device name for whatever reason
|
||||||
# write command seems to only accept a single word, so this is fine;
|
# write command seems to only accept a single word, so this is fine;
|
||||||
# we just hardcode the number of bytes read to two here.
|
# we just hardcode the number of bytes read to two here.
|
||||||
|
@ -176,14 +178,18 @@ def writeMemory(fh: BaseInterface, address: int, data: bytes):
|
||||||
try:
|
try:
|
||||||
crc = struct.unpack_from("<H", _crc)[0]
|
crc = struct.unpack_from("<H", _crc)[0]
|
||||||
except struct.error:
|
except struct.error:
|
||||||
log(f"writeMemory: CRC error; read {len(_crc)} bytes (2 expected)")
|
logger.error(
|
||||||
|
f"writeMemory: CRC error; read {len(_crc)} bytes (2 expected)"
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
calculated_crc = modbus(bytes([tag, operation, size, address, *rdata]))
|
calculated_crc = modbus(bytes([tag, operation, size, address, *rdata]))
|
||||||
if crc == calculated_crc:
|
if crc == calculated_crc:
|
||||||
return rdata
|
return rdata
|
||||||
else:
|
else:
|
||||||
log(f"writeMemory: CRC error; {crc:04X} != {calculated_crc:04X}")
|
logger.error(
|
||||||
log("data or crc is falsely", header, rdata, _crc)
|
f"writeMemory: CRC error; {crc:04X} != {calculated_crc:04X}"
|
||||||
|
)
|
||||||
|
logger.error("data or crc is falsely %s %s %s", header, rdata, _crc)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -193,7 +199,6 @@ def writeMemoryMultiple(fh: BaseInterface, address: int, data: bytes):
|
||||||
res = bytearray()
|
res = bytearray()
|
||||||
for i in range(len(data) // 2):
|
for i in range(len(data) // 2):
|
||||||
d = data[i * 2 : (i + 1) * 2]
|
d = data[i * 2 : (i + 1) * 2]
|
||||||
log(address + i, d)
|
|
||||||
r = writeMemory(fh, address + i, d)
|
r = writeMemory(fh, address + i, d)
|
||||||
if r:
|
if r:
|
||||||
res.extend(r)
|
res.extend(r)
|
||||||
|
@ -214,15 +219,16 @@ def try_read_parse(
|
||||||
try:
|
try:
|
||||||
if parser:
|
if parser:
|
||||||
return parser(res)
|
return parser(res)
|
||||||
except struct.error as e:
|
except struct.error:
|
||||||
log(e)
|
logger.exception("0x0100 Unpack error: %s %s", len(res), res)
|
||||||
log("0x0100 Unpack error:", len(res), res)
|
|
||||||
_timeout = dev.timeout
|
_timeout = dev.timeout
|
||||||
dev.timeout = 0.5
|
dev.timeout = 0.5
|
||||||
log("Flushed from read buffer; ", dev.read())
|
logger.warning("Flushed from read buffer; %s", dev.read())
|
||||||
dev.timeout = _timeout
|
dev.timeout = _timeout
|
||||||
else:
|
else:
|
||||||
log(f"No data read, expected {words*2} bytes (attempts left: {attempts})")
|
logger.warning(
|
||||||
|
f"No data read, expected {words*2} bytes (attempts left: {attempts})"
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,7 +314,6 @@ class ChargeController:
|
||||||
# Pad name to 32 bytes to ensure ensure nothing is left of old name
|
# Pad name to 32 bytes to ensure ensure nothing is left of old name
|
||||||
while len(bin_value) < 32:
|
while len(bin_value) < 32:
|
||||||
bin_value.extend(b"\x00\x20")
|
bin_value.extend(b"\x00\x20")
|
||||||
print(len(bin_value), bin_value)
|
|
||||||
|
|
||||||
data = writeMemoryMultiple(self.device, 0x0049, bin_value)
|
data = writeMemoryMultiple(self.device, 0x0049, bin_value)
|
||||||
if data is None:
|
if data is None:
|
||||||
|
@ -316,7 +321,7 @@ class ChargeController:
|
||||||
|
|
||||||
res = data.decode("UTF-16BE").strip()
|
res = data.decode("UTF-16BE").strip()
|
||||||
if res != value:
|
if res != value:
|
||||||
log(f"setting device name failed; {res!r} != {value!r}")
|
logger.error("setting device name failed; %r != %r", res, value)
|
||||||
self._cached_name = value
|
self._cached_name = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -333,9 +338,9 @@ class ChargeController:
|
||||||
if data is not None:
|
if data is not None:
|
||||||
res = struct.unpack("x?", data)[0]
|
res = struct.unpack("x?", data)[0]
|
||||||
if res != value:
|
if res != value:
|
||||||
log(f"setting load_enabled failed; {res!r} != {value!r}")
|
logger.error("setting load_enabled failed; %r != %r", res, value)
|
||||||
else:
|
else:
|
||||||
log("setting load_enabled failed; communications error")
|
logger.error("setting load_enabled failed; communications error")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self) -> ChargerState:
|
def state(self) -> ChargerState:
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import datetime
|
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
from logging import getLogger
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
# Only factor of 1000
|
# Only factor of 1000
|
||||||
SI_PREFIXES_LARGE = "kMGTPEZY"
|
SI_PREFIXES_LARGE = "kMGTPEZY"
|
||||||
SI_PREFIXES_SMALL = "mµnpfazy"
|
SI_PREFIXES_SMALL = "mµnpfazy"
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def humanize_number(data, unit: str = ""):
|
def humanize_number(data, unit: str = ""):
|
||||||
counter = 0
|
counter = 0
|
||||||
|
@ -35,11 +35,6 @@ def humanize_number(data, unit: str = ""):
|
||||||
return f"{data:.3g} {prefix}{unit}"
|
return f"{data:.3g} {prefix}{unit}"
|
||||||
|
|
||||||
|
|
||||||
def log(*message: object, **kwargs):
|
|
||||||
print(datetime.datetime.utcnow().isoformat(" "), *message, **kwargs)
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
class Periodical:
|
class Periodical:
|
||||||
prev: float
|
prev: float
|
||||||
interval: float
|
interval: float
|
||||||
|
@ -56,7 +51,9 @@ class Periodical:
|
||||||
skipped, overshoot = divmod(now - self.prev, self.interval)
|
skipped, overshoot = divmod(now - self.prev, self.interval)
|
||||||
skipped -= 1
|
skipped -= 1
|
||||||
if skipped:
|
if skipped:
|
||||||
log("Skipped:", skipped, overshoot, now - self.prev, self.interval)
|
logger.debug(
|
||||||
|
"Skipped:", skipped, overshoot, now - self.prev, self.interval
|
||||||
|
)
|
||||||
self.prev = now - overshoot
|
self.prev = now - overshoot
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue