Skip to content

Commit

Permalink
refactor, add wifi, add local ip
Browse files Browse the repository at this point in the history
  • Loading branch information
JarbasAl committed Nov 7, 2023
1 parent c3b886f commit 8a4699e
Show file tree
Hide file tree
Showing 20 changed files with 373 additions and 227 deletions.
144 changes: 27 additions & 117 deletions ovos_PHAL_sensors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
import concurrent.futures
import time
from threading import Event
from typing import List

from ovos_config import Configuration
from ovos_plugin_manager.templates.phal import PHALPlugin

from ovos_PHAL_sensors.base import Sensor, BooleanSensor, BusSensor
from ovos_PHAL_sensors.battery import BatterySensor
from ovos_PHAL_sensors.cpu import CPUCountSensor, \
from ovos_PHAL_sensors.device import BaseDevice
from ovos_PHAL_sensors.device import BaseDevice
from ovos_PHAL_sensors.loggers import MessageBusLogger, FileSensorLogger
from ovos_PHAL_sensors.loggers.ha_http import HomeAssistantUpdater
from ovos_PHAL_sensors.sensors.base import Sensor, BusSensor
from ovos_PHAL_sensors.sensors.battery import BatterySensor
from ovos_PHAL_sensors.sensors.cpu import CPUCountSensor, \
CPUTemperatureSensor, CPUUsageSensor
from ovos_PHAL_sensors.fan import CpuFanSensor, GpuFanSensor
from ovos_PHAL_sensors.loggers import HomeAssistantUpdater, MessageBusLogger, FileSensorLogger
from ovos_PHAL_sensors.memory import SwapTotalSensor, SwapUsageSensor, \
from ovos_PHAL_sensors.sensors.extra.blue import BlueScanner, bluetooth
from ovos_PHAL_sensors.sensors.extra.pulse import PAVersionSensor, PAHostnameSensor, PAPlaybackSensor, \
PAChannelCountSensor, \
PADefaultSinkSensor, PADefaultSourceSensor, PANowPlayingSensor, \
PABluezActiveSensor, PABluezConnectedSensor, PAAudioPlayingSensor, pulse
from ovos_PHAL_sensors.sensors.extra.screen import ScreenBrightnessSensor, sbc
from ovos_PHAL_sensors.sensors.fan import CpuFanSensor, GpuFanSensor
from ovos_PHAL_sensors.sensors.memory import SwapTotalSensor, SwapUsageSensor, \
DiskPercentSensor, DiskTotalSensor, DiskUsageSensor, \
MemoryTotalSensor, MemoryUsageSensor
from ovos_PHAL_sensors.network import ExternalIPSensor
from ovos_PHAL_sensors.os_system import MachineSensor, ArchitectureSensor, OSSystemSensor, \
from ovos_PHAL_sensors.sensors.network import ExternalIPSensor, LocalIPSensor
from ovos_PHAL_sensors.sensors.os_system import MachineSensor, ArchitectureSensor, OSSystemSensor, \
OSNameSensor, ReleaseSensor, BootTimeSensor
from ovos_PHAL_sensors.procs import SystemdSensor, DBUSDaemonSensor, KDEConnectSensor, \
from ovos_PHAL_sensors.sensors.procs import SystemdSensor, DBUSDaemonSensor, KDEConnectSensor, \
PipewireSensor, PulseAudioSensor, PlasmaShellSensor, FirefoxSensor, SpotifySensor, \
MiniDLNASensor, UPMPDCliSensor
from ovos_PHAL_sensors.pulse import PAVersionSensor, PAHostnameSensor, PAPlaybackSensor, PAChannelCountSensor, \
PADefaultSinkSensor, PADefaultSourceSensor, PANowPlayingSensor, \
PABluezActiveSensor, PABluezConnectedSensor, PAAudioPlayingSensor, pulse
from ovos_PHAL_sensors.screen import ScreenBrightnessSensor, sbc
from ovos_PHAL_sensors.blue import BlueScanner, bluetooth, BluetoothSpeakerConnected


class OVOSDevice:
class OVOSDevice(BaseDevice):

def __init__(self, name, screen=True, battery=True,
memory=True, cpu=True, network=True, fan=True,
os=True, apps=True, pa=True, blue=True):
os=True, apps=True, pa=True, blue=True, wifi=True):
if pulse is None:
pa = False
if bluetooth is None:
blue = False
if sbc is None:
screen = False
# TODO - if is_docker -> disable apps
self.name = name
self.screen = screen
self.battery = battery
self.cpu = cpu
Expand All @@ -49,48 +49,19 @@ def __init__(self, name, screen=True, battery=True,
self.fan = fan
self.os = os
self.apps = apps
self.wifi = wifi
if blue:
self.blue = BlueScanner(daemon=True, device_name=name)
self.blue.start()
else:
self.blue = None
self.pa = pa

self._readings = {}
self._ts = {}
self._workers = 6

@classmethod
def bind(cls, name, ha_url, ha_token, bus=None, disable_bus=False, disable_ha=False, disable_file_logger=True):
Sensor.device_name = name

# setup home assistant
if not ha_token or not ha_url: # check HA plugin config
cfg = Configuration().get("PHAL", {}).get(
"ovos-PHAL-plugin-homeassistant", {})
if "api_key" in cfg and not ha_token:
ha_token = cfg["api_key"]
if "host" in cfg and not ha_url:
ha_url = cfg["host"]

if ha_url and ha_token:
HomeAssistantUpdater.ha_url = ha_url
HomeAssistantUpdater.ha_token = ha_token
if not disable_ha:
Sensor.bind_logger(HomeAssistantUpdater)
if not disable_file_logger:
Sensor.bind_logger(FileSensorLogger)

# connect messagebus
if bus:
cls.bus = bus
BusSensor.bind(bus)
MessageBusLogger.bus = bus
if not disable_bus:
Sensor.bind_logger(MessageBusLogger)
super().__init__(name)

@property
def sensors(self) -> List[Sensor]:
# TODO - plugins
sensors = []
if self.pa:
sensors += [PAHostnameSensor(), PAVersionSensor(), PAChannelCountSensor(),
Expand Down Expand Up @@ -122,80 +93,21 @@ def sensors(self) -> List[Sensor]:
CPUCountSensor()
]
if self.network:
sensors += [ExternalIPSensor()]
sensors += [ExternalIPSensor(), LocalIPSensor()]
if self.screen:
sensors += [ScreenBrightnessSensor()]
if self.battery:
sensors += [BatterySensor()]
if self.fan:
sensors += [CpuFanSensor(), GpuFanSensor()]

# inject device name prefix
for s in sensors:
s.device_name = f"{self.name}_{s.device_name}"

# no inject device name, sensors managed by bluescanner
if self.blue is not None:
sensors += self.blue.sensors

if self.wifi:
from ovos_PHAL_sensors.sensors.extra.wifiscan import scan_wifi
sensors += scan_wifi(self.name)
return sensors

def _parallel_readings(self, do_reading):
results = {}

# do the work in parallel instead of sequentially
with concurrent.futures.ThreadPoolExecutor(max_workers=self._workers) as executor:

matchers = {}
# create a unique wrapper for each worker with their arguments
for sensor in self.sensors:
if sensor._thread_safe:
def do_thing(u=sensor):
return do_reading(u)

matchers[sensor.unique_id] = do_thing

# Start the operations and mark each future with its source
future_to_source = {
executor.submit(func): device_id
for device_id, func in matchers.items()
}

# retrieve results as they come
for future in concurrent.futures.as_completed(future_to_source):
future.result()

# do sequential read for non thread safe sensors
for sensor in self.sensors:
if not sensor._thread_safe:
do_reading(sensor)
return results

def update(self):

def get_reading(sensor):
if sensor.unique_id not in self._readings:
self._readings[sensor.unique_id] = sensor.value
self._ts[sensor.unique_id] = time.time()
old = None
else:
if sensor._once:
# print("skipping", sensor.unique_id)
return # doesnt change
if sensor._slow and time.time() - self._ts[sensor.unique_id] < 15 * 60:
# print("skipping", sensor.unique_id)
return # track timestamp and do once/hour
old = self._readings[sensor.unique_id]

if old is None or old != sensor.value:
try:
sensor.sensor_update()
self._ts[sensor.unique_id] = time.time()
except Exception as e:
print(e)

self._parallel_readings(get_reading)


class PHALSensors(PHALPlugin):
def __init__(self, bus, name="phal_sensors", config=None):
Expand Down Expand Up @@ -230,5 +142,3 @@ def run(self):
while self.running:
self.device.update()
Event().wait(self.sleep)


116 changes: 116 additions & 0 deletions ovos_PHAL_sensors/device.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import abc
import concurrent.futures
import time
from typing import List

from ovos_config import Configuration

from ovos_PHAL_sensors.loggers import MessageBusLogger, FileSensorLogger
from ovos_PHAL_sensors.loggers.ha_http import HomeAssistantUpdater
from ovos_PHAL_sensors.sensors.base import Sensor, BusSensor


class BaseDevice:
""" A device is a collection of sensors
a prefix gets added to the sensors unique_id for this device """

def __init__(self, name, prefix=True):
self.name = name
self._readings = {}
self._ts = {}
self._workers = 6
self.prefix = prefix

@classmethod
def bind(cls, name, ha_url, ha_token, bus=None,
disable_bus=False, disable_ha=False, disable_file_logger=True):
Sensor.device_name = name

# setup home assistant
if not ha_token or not ha_url: # check HA plugin config
cfg = Configuration().get("PHAL", {}).get(
"ovos-PHAL-plugin-homeassistant", {})
if "api_key" in cfg and not ha_token:
ha_token = cfg["api_key"]
if "host" in cfg and not ha_url:
ha_url = cfg["host"]

if ha_url and ha_token:
HomeAssistantUpdater.ha_url = ha_url
HomeAssistantUpdater.ha_token = ha_token
if not disable_ha:
Sensor.bind_logger(HomeAssistantUpdater)
if not disable_file_logger:
Sensor.bind_logger(FileSensorLogger)

# connect messagebus
if bus:
cls.bus = bus
BusSensor.bind(bus)
MessageBusLogger.bus = bus
if not disable_bus:
Sensor.bind_logger(MessageBusLogger)

@property
@abc.abstractmethod
def sensors(self) -> List[Sensor]:
return []

def _parallel_readings(self, do_reading):
results = {}

# do the work in parallel instead of sequentially
with concurrent.futures.ThreadPoolExecutor(max_workers=self._workers) as executor:

matchers = {}
# create a unique wrapper for each worker with their arguments
for sensor in self.sensors:
if self.prefix and sensor._allow_prefix:
sensor.device_name = f"{self.name}_{sensor.device_name}"

if sensor._thread_safe:
def do_thing(u=sensor):
return do_reading(u)

matchers[sensor.unique_id] = do_thing

# Start the operations and mark each future with its source
future_to_source = {
executor.submit(func): device_id
for device_id, func in matchers.items()
}

# retrieve results as they come
for future in concurrent.futures.as_completed(future_to_source):
future.result()

# do sequential read for non thread safe sensors
for sensor in self.sensors:
if not sensor._thread_safe:
do_reading(sensor)
return results

def update(self):

def get_reading(sensor):
if sensor.unique_id not in self._readings:
self._readings[sensor.unique_id] = sensor.value
self._ts[sensor.unique_id] = time.time()
old = None
else:
if sensor._once:
# print("skipping", sensor.unique_id)
return # doesnt change
if sensor._slow and time.time() - self._ts[sensor.unique_id] < 15 * 60:
# print("skipping", sensor.unique_id)
return # track timestamp and do once/hour
old = self._readings[sensor.unique_id]

if old is None or old != sensor.value:
try:
sensor.sensor_update()
self._ts[sensor.unique_id] = time.time()
except Exception as e:
print(e)

self._parallel_readings(get_reading)
2 changes: 2 additions & 0 deletions ovos_PHAL_sensors/loggers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from ovos_PHAL_sensors.loggers.base import SensorLogger, FileSensorLogger, MessageBusLogger
from ovos_PHAL_sensors.loggers.ha_http import HomeAssistantUpdater
Loading

0 comments on commit 8a4699e

Please sign in to comment.