test
This commit is contained in:
23
sambanas/rootfs/usr/local/bin/disklist.py
Normal file
23
sambanas/rootfs/usr/local/bin/disklist.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# python 3.11
|
||||
|
||||
# Return the list of mountable external Devices
|
||||
|
||||
from diskinfo import DiskInfo
|
||||
|
||||
|
||||
di = DiskInfo()
|
||||
disks = di.get_disk_list(sorting=True)
|
||||
regex = r"Name:\s+(\w+)\s.*\n"
|
||||
for d in disks:
|
||||
if d.get_partition_table_type() == "":
|
||||
continue
|
||||
plist = d.get_partition_list()
|
||||
for item in plist:
|
||||
label = item.get_fs_label()
|
||||
if label.startswith("hassos"):
|
||||
continue
|
||||
elif label != "":
|
||||
print(item.get_fs_label())
|
||||
elif item.get_fs_type() == "apfs":
|
||||
print("id:{uuid}".format(uuid=item.get_fs_uuid()))
|
||||
# print(item.get_fs_label()," ",item.get_fs_type()," ",item.get_part_uuid()," ",item.get_name())
|
650
sambanas/rootfs/usr/local/bin/mqtt_daemon.py
Normal file
650
sambanas/rootfs/usr/local/bin/mqtt_daemon.py
Normal file
@@ -0,0 +1,650 @@
|
||||
# python 3.11
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
import time
|
||||
import argparse
|
||||
import collections
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import typing
|
||||
import hashlib
|
||||
from pySMART import DeviceList, Device
|
||||
from pySMART.interface import NvmeAttributes, AtaAttributes
|
||||
import psutil
|
||||
from psutil._common import sdiskio, sdiskusage
|
||||
from ha_mqtt_discoverable import Settings, DeviceInfo
|
||||
from ha_mqtt_discoverable.sensors import Sensor, SensorInfo, BinarySensor
|
||||
from ha_mqtt_discoverable.sensors import BinarySensorInfo
|
||||
import signal
|
||||
from typing import Any, Callable, List, Literal, NoReturn, Self, Tuple, Union
|
||||
import re
|
||||
import humanize
|
||||
from abc import ABC, abstractmethod
|
||||
from diskinfo import Disk
|
||||
|
||||
# config = configparser.ConfigParser( strict=False )
|
||||
# config.read("/etc/samba/smb.conf")
|
||||
|
||||
# Get the arguments from the command-line except the filename
|
||||
ap = argparse.ArgumentParser()
|
||||
|
||||
# Add the arguments to the parser
|
||||
ap.add_argument("-b", "--broker", required=True, help="Broker")
|
||||
ap.add_argument("-p", "--port", required=True, help="Broker Port")
|
||||
ap.add_argument("-u", "--user", required=True, help="Broker User")
|
||||
ap.add_argument("-P", "--password", required=True, help="Broker Password")
|
||||
ap.add_argument("-t", "--topic", required=False, help="Topic", default="sambanas")
|
||||
ap.add_argument(
|
||||
"-i",
|
||||
"--hdidle_log",
|
||||
required=False,
|
||||
help="HD_IDLE log to listen for sleeping drivers",
|
||||
)
|
||||
ap.add_argument(
|
||||
"-T", "--discovery_topic", required=False, help="Topic", default="homeassistant"
|
||||
)
|
||||
ap.add_argument(
|
||||
"-d", "--persist_discovery", required=False, help="Topic", default=True, type=bool
|
||||
)
|
||||
ap.add_argument(
|
||||
"-v", "--addon_version", required=False, help="Addon Version", default="latest"
|
||||
)
|
||||
ap.add_argument(
|
||||
"-l",
|
||||
"--logLevel",
|
||||
required=False,
|
||||
default="WARNING",
|
||||
choices=[
|
||||
"ALL",
|
||||
"TRACE",
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"NOTICE",
|
||||
"WARNING",
|
||||
"ERROR",
|
||||
"CRITICAL",
|
||||
"FATAL",
|
||||
"OFF",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
args: dict[str, Any] = vars(ap.parse_args())
|
||||
|
||||
|
||||
match str(args["logLevel"]).upper():
|
||||
case "DEBUG" | "ALL" | "TRACE":
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
case "NOTICE":
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
case "WARNING" | "INFO":
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
case "ERROR":
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
case "CRITICAL" | "FATAL":
|
||||
logging.basicConfig(level=logging.CRITICAL)
|
||||
case "OFF":
|
||||
logging.basicConfig(level=logging.NOTSET)
|
||||
case "_":
|
||||
logging.basicConfig(level=logging.WARNING)
|
||||
|
||||
mqtt_settings = Settings.MQTT(
|
||||
host=args["broker"],
|
||||
port=int(args["port"]),
|
||||
username=args["user"],
|
||||
password=args["password"],
|
||||
discovery_prefix=args["discovery_topic"],
|
||||
state_prefix=args["topic"],
|
||||
)
|
||||
|
||||
|
||||
# Global Sensors regitry
|
||||
class ConfigEntity(ABC):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
self.sensorInfo: SensorInfo | BinarySensorInfo = sensorInfo
|
||||
self.state_function = state_function
|
||||
self.attributes_function = attributes_function
|
||||
self.sensor: Union[Sensor, BinarySensor] = None # type: ignore
|
||||
|
||||
def createSensor(self) -> Self:
|
||||
if self.sensor is not None:
|
||||
return self.sensor # type: ignore
|
||||
settings = Settings(mqtt=mqtt_settings, entity=self.sensorInfo)
|
||||
if isinstance(self.sensorInfo, BinarySensorInfo):
|
||||
self.sensor = BinarySensor(settings) # type: ignore
|
||||
logging.debug(
|
||||
"BinarySensor '%s' created", self.sensor.generate_config()["name"]
|
||||
)
|
||||
elif isinstance(self.sensorInfo, SensorInfo):
|
||||
self.sensor = Sensor(settings) # type: ignore
|
||||
logging.debug("Sensor '%s' created", self.sensor.generate_config()["name"])
|
||||
return self
|
||||
|
||||
@abstractmethod
|
||||
def detstroy(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class ConfigEntityAutonomous(ConfigEntity):
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromDevice(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
device: Device,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] = None, # type: ignore
|
||||
):
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.device = device
|
||||
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromHDIdle(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
device: Device,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] = None, # type: ignore
|
||||
):
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.device = device
|
||||
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromIoStat(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
iostat_device: str,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.iostat_device: str = iostat_device
|
||||
self._iostat: collections.deque[tuple[int, dict[str, sdiskio] | None]] = (
|
||||
collections.deque([(0, None), (0, None)], maxlen=2)
|
||||
)
|
||||
|
||||
@property
|
||||
def iostat(self) -> tuple[int, dict[str, sdiskio] | None]:
|
||||
return self._iostat[1]
|
||||
|
||||
@property
|
||||
def h_iostat(self) -> tuple[int, dict[str, sdiskio] | None]:
|
||||
return self._iostat[0]
|
||||
|
||||
def addIostat(self, iostat: dict) -> None:
|
||||
self._iostat.append((time.time_ns(), iostat.copy()))
|
||||
|
||||
def detstroy(self) -> None:
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
class ConfigEntityFromSamba(ConfigEntity):
|
||||
def __init__(
|
||||
self,
|
||||
sensorInfo: Union[SensorInfo, BinarySensorInfo],
|
||||
samba: dict,
|
||||
state_function: Callable[[Self], Any],
|
||||
attributes_function: Callable[[Self], dict[str, Any]] | None = None,
|
||||
) -> None:
|
||||
super().__init__(sensorInfo, state_function, attributes_function)
|
||||
self.samba = samba
|
||||
|
||||
def detstroy(self):
|
||||
self.sensor.delete()
|
||||
|
||||
|
||||
def sambaMetricCollector() -> dict[str, Any]:
|
||||
# smbstatus gets report of current samba server connections
|
||||
try:
|
||||
p = subprocess.Popen(["smbstatus", "-jf"], stdout=subprocess.PIPE)
|
||||
output, err = p.communicate()
|
||||
jsondata = json.loads(output.decode())
|
||||
|
||||
logging.debug("SmbClient: %s", jsondata)
|
||||
except Exception:
|
||||
logging.warning("Exception on smbstat comunication!")
|
||||
jsondata = {}
|
||||
|
||||
data = {"samba_version": jsondata.get("version", "Unknown")}
|
||||
if "sessions" in jsondata:
|
||||
data["users"] = len(jsondata["sessions"])
|
||||
data["users_json"] = jsondata["sessions"]
|
||||
else:
|
||||
data["users"] = 0
|
||||
data["users_json"] = {}
|
||||
|
||||
data["connections"] = len(jsondata["tcons"]) if "tcons" in jsondata else 0
|
||||
if "open_files" in jsondata:
|
||||
data["open_files"] = len(jsondata["open_files"])
|
||||
else:
|
||||
data["open_files"] = 0
|
||||
|
||||
logging.debug(data)
|
||||
return data
|
||||
|
||||
|
||||
sensorList: List[Tuple[str, ConfigEntity]] = []
|
||||
devicePowerStatus: dict[str, str] = {}
|
||||
|
||||
# Main device SambaNas
|
||||
samba: dict[str, Any] = sambaMetricCollector()
|
||||
sambanas_device_info = DeviceInfo(
|
||||
name="SambaNas",
|
||||
model="Addon",
|
||||
manufacturer="@Dianlight",
|
||||
sw_version=samba["samba_version"],
|
||||
hw_version=args["addon_version"],
|
||||
identifiers=[os.getenv("HOSTNAME", default="local_test")],
|
||||
)
|
||||
|
||||
devlist = DeviceList()
|
||||
psdata: dict[str, sdiskio] = psutil.disk_io_counters(perdisk=True, nowrap=True)
|
||||
|
||||
for dev_name in psdata.keys():
|
||||
if re.search(r"\d+$", dev_name):
|
||||
continue
|
||||
dev = Device(dev_name)
|
||||
disk_device_info = DeviceInfo(
|
||||
name=f"SambaNas Disk {dev_name}",
|
||||
model=dev.model,
|
||||
sw_version=dev.firmware,
|
||||
# connections=[[dev_name,sambanas_device_info.identifiers[0]]],
|
||||
identifiers=[dev.serial or "Unknown(%s)" % dev_name],
|
||||
via_device=sambanas_device_info.identifiers[0], # type: ignore
|
||||
)
|
||||
|
||||
# sambanas_device_info.connections.append([dev_name,disk_device_info.identifiers[0]])
|
||||
|
||||
def smartAssesmentAttribute(ce: ConfigEntityFromDevice) -> dict[str, Any]:
|
||||
attributes: dict[str, Any] = {
|
||||
"smart_capable": ce.device.smart_capable,
|
||||
"smart_enabled": ce.device.smart_enabled,
|
||||
"assessment": ce.device.assessment,
|
||||
"messages": ce.device.messages,
|
||||
"rotation_rate": ce.device.rotation_rate,
|
||||
"_test_running": ce.device._test_running,
|
||||
"_test_progress": ce.device._test_progress,
|
||||
}
|
||||
if ce.device.if_attributes is None:
|
||||
return attributes
|
||||
if isinstance(ce.device.if_attributes, AtaAttributes):
|
||||
atattrs: AtaAttributes = ce.device.if_attributes
|
||||
for atattr in atattrs.legacyAttributes:
|
||||
if atattr is None:
|
||||
continue
|
||||
attributes[atattr.name] = atattr.raw
|
||||
health_value: Literal["OK", "FAIL"] = (
|
||||
"OK"
|
||||
if (atattr.thresh is not None and atattr.worst > atattr.thresh)
|
||||
else "FAIL"
|
||||
)
|
||||
attributes[f"{atattr.name}_Health"] = health_value
|
||||
elif isinstance(ce.device.if_attributes, NvmeAttributes):
|
||||
nwmattrs: NvmeAttributes = ce.device.if_attributes
|
||||
for nwmattr in nwmattrs.__dict__.keys():
|
||||
if nwmattrs.__dict__[nwmattr] is None:
|
||||
continue
|
||||
attributes[nwmattr] = nwmattrs.__dict__[nwmattr]
|
||||
return attributes
|
||||
|
||||
if dev.smart_capable:
|
||||
smartAssessment = ConfigEntityFromDevice(
|
||||
sensorInfo=BinarySensorInfo(
|
||||
name=f"S.M.A.R.T {dev.name}",
|
||||
unique_id=hashlib.md5(
|
||||
f"S.M.A.R.T {dev.name}".encode("utf-8")
|
||||
).hexdigest(),
|
||||
device=disk_device_info,
|
||||
# enabled_by_default= dev.smart_capable
|
||||
device_class="problem",
|
||||
),
|
||||
state_function=lambda ce: ce.device.assessment != "PASS",
|
||||
attributes_function=smartAssesmentAttribute,
|
||||
device=dev,
|
||||
)
|
||||
sensorList.append((f"smart_{dev.name}", smartAssessment.createSensor()))
|
||||
|
||||
if args["hdidle_log"] is not None:
|
||||
hdIdleAssessment = ConfigEntityFromHDIdle(
|
||||
sensorInfo=BinarySensorInfo(
|
||||
name=f"POWER {dev.name}",
|
||||
unique_id=hashlib.md5(f"POWER {dev.name}".encode("utf-8")).hexdigest(),
|
||||
device=disk_device_info,
|
||||
device_class="power",
|
||||
),
|
||||
state_function=lambda ce: devicePowerStatus.get(ce.device.name) != "spindown",
|
||||
attributes_function=lambda ce: {"pipe_file": args["hdidle_log"] + "s"},
|
||||
device=dev,
|
||||
)
|
||||
sensorList.append((f"power_{dev.name}", hdIdleAssessment.createSensor()))
|
||||
|
||||
def totalDiskRate(ce: ConfigEntityFromIoStat) -> float | Literal[0]:
|
||||
|
||||
if (
|
||||
ce.h_iostat[0] in [0, ce.iostat[0]] or ce.iostat[1] is None or ce.h_iostat[1] is None
|
||||
):
|
||||
return 0
|
||||
t_read: int = int(ce.iostat[1][ce.iostat_device].read_bytes) - int(
|
||||
ce.h_iostat[1][ce.iostat_device].read_bytes
|
||||
)
|
||||
t_write: int = int(ce.iostat[1][ce.iostat_device].write_bytes) - int(
|
||||
ce.h_iostat[1][ce.iostat_device].write_bytes
|
||||
)
|
||||
t_ns_time: int = ce.iostat[0] - ce.h_iostat[0]
|
||||
logging.debug("%s %d %d %d", ce.iostat_device, t_read, t_write, t_ns_time)
|
||||
return round(((t_read + t_write) * 1000000000 / t_ns_time) / 1024, 2) # kB/s
|
||||
|
||||
def iostatAttribute(ce: ConfigEntityFromIoStat) -> dict[str, str]:
|
||||
if ce.iostat[1] is None:
|
||||
return {}
|
||||
attributes: dict[str, str] = {
|
||||
key: getattr(ce.iostat[1][ce.iostat_device], key)
|
||||
for key in ce.iostat[1][ce.iostat_device]._fields
|
||||
}
|
||||
return attributes
|
||||
|
||||
diskInfo = ConfigEntityFromIoStat(
|
||||
sensorInfo=SensorInfo(
|
||||
name=f"IOSTAT {dev.name}",
|
||||
unique_id=hashlib.md5(f"IOSTAT {dev.name}".encode("utf-8")).hexdigest(),
|
||||
device=disk_device_info,
|
||||
unit_of_measurement="kB/s",
|
||||
device_class="data_rate",
|
||||
),
|
||||
state_function=totalDiskRate,
|
||||
attributes_function=iostatAttribute,
|
||||
iostat_device=dev.name,
|
||||
)
|
||||
|
||||
sensorList.append((f"iostat_{dev.name}", diskInfo.createSensor()))
|
||||
|
||||
partitionDevices: typing.Dict[str, DeviceInfo] = {}
|
||||
|
||||
for partition in Disk(dev_name).get_partition_list():
|
||||
if (partition.get_fs_label() or partition.get_fs_uuid()) == "":
|
||||
continue
|
||||
if not partition.get_name() in partitionDevices:
|
||||
partitionDevices[partition.get_name()] = DeviceInfo(
|
||||
name=f"SambaNas Partition {partition.get_fs_label() or partition.get_fs_uuid()}",
|
||||
model=partition.get_fs_label() or partition.get_fs_uuid(),
|
||||
manufacturer=partition.get_fs_type(),
|
||||
identifiers=[partition.get_fs_label() or partition.get_fs_uuid()],
|
||||
via_device=disk_device_info.identifiers[0], # type: ignore
|
||||
)
|
||||
try:
|
||||
sdiskparts = list(
|
||||
filter(
|
||||
lambda part: part.device.endswith(partition.get_name()),
|
||||
psutil.disk_partitions(),
|
||||
)
|
||||
)
|
||||
if sdiskparts and sdiskparts[0] and sdiskparts[0].mountpoint:
|
||||
if partitionDevices[partition.get_name()].identifiers is None:
|
||||
partitionDevices[partition.get_name()].identifiers = []
|
||||
if isinstance(partitionDevices[partition.get_name()].identifiers, str):
|
||||
partitionDevices[partition.get_name()].identifiers = [
|
||||
str(partitionDevices[partition.get_name()].identifiers)
|
||||
]
|
||||
partitionDevices[partition.get_name()].identifiers.append( # type: ignore
|
||||
sdiskparts[0].mountpoint
|
||||
)
|
||||
finally:
|
||||
pass
|
||||
|
||||
logging.debug(
|
||||
"Generated %d Partitiond Device for %s", len(partitionDevices), dev.name
|
||||
)
|
||||
|
||||
for partition_device, partitionDeviceInfo in partitionDevices.items():
|
||||
partitionInfo = ConfigEntityFromIoStat(
|
||||
sensorInfo=SensorInfo(
|
||||
name=f"IOSTAT {partitionDeviceInfo.model}",
|
||||
unique_id=hashlib.md5(
|
||||
f"IOSTAT {partitionDeviceInfo.model}".encode("utf-8")
|
||||
).hexdigest(),
|
||||
device=partitionDeviceInfo,
|
||||
unit_of_measurement="kB/s",
|
||||
device_class="data_rate",
|
||||
),
|
||||
state_function=totalDiskRate,
|
||||
attributes_function=iostatAttribute,
|
||||
iostat_device=partition_device,
|
||||
)
|
||||
|
||||
sensorList.append((f"iostat_{partition_device}", partitionInfo.createSensor()))
|
||||
|
||||
def usageAttribute(ce: ConfigEntityAutonomous) -> dict[str, str]:
|
||||
if ce.sensorInfo.device is None or ce.sensorInfo.device.identifiers is None:
|
||||
return {}
|
||||
usage: sdiskusage = psutil.disk_usage(ce.sensorInfo.device.identifiers[-1])
|
||||
attributes: dict[str, str] = {
|
||||
"used": humanize.naturalsize(usage.used),
|
||||
"total": humanize.naturalsize(usage.total),
|
||||
"free": humanize.naturalsize(usage.free),
|
||||
}
|
||||
return attributes
|
||||
|
||||
def partitionUsage(ce: ConfigEntityAutonomous) -> Any:
|
||||
if ce.sensorInfo.device is None or ce.sensorInfo.device.identifiers is None:
|
||||
return
|
||||
logging.debug(
|
||||
"Collecting Usage from %s [%s]",
|
||||
ce.sensorInfo.device.identifiers,
|
||||
ce.sensorInfo.device.identifiers[-1],
|
||||
)
|
||||
return psutil.disk_usage(ce.sensorInfo.device.identifiers[-1]).percent
|
||||
|
||||
if (
|
||||
partitionDeviceInfo.identifiers is not None and len(partitionDeviceInfo.identifiers) > 1
|
||||
):
|
||||
partitionInfo = ConfigEntityAutonomous(
|
||||
sensorInfo=SensorInfo(
|
||||
name=f"Usage {partitionDeviceInfo.model}",
|
||||
unique_id=hashlib.md5(
|
||||
f"Usage {partitionDeviceInfo.model}".encode("utf-8")
|
||||
).hexdigest(),
|
||||
device=partitionDeviceInfo,
|
||||
icon="mdi:harddisk",
|
||||
unit_of_measurement="%",
|
||||
device_class="power_factor",
|
||||
),
|
||||
state_function=partitionUsage,
|
||||
attributes_function=usageAttribute,
|
||||
)
|
||||
|
||||
sensorList.append(
|
||||
(f"usage_{partition_device}", partitionInfo.createSensor())
|
||||
)
|
||||
|
||||
sambaUsers = ConfigEntityFromSamba(
|
||||
sensorInfo=SensorInfo(
|
||||
name="Online Users",
|
||||
device=sambanas_device_info,
|
||||
unique_id=hashlib.md5("Online Users".encode("utf-8")).hexdigest(),
|
||||
),
|
||||
state_function=lambda ce: ce.samba["users"],
|
||||
samba=samba,
|
||||
)
|
||||
sensorList.append(("samba_users", sambaUsers.createSensor()))
|
||||
sambaConnections = ConfigEntityFromSamba(
|
||||
sensorInfo=SensorInfo(
|
||||
name="Active Connections",
|
||||
device=sambanas_device_info,
|
||||
unique_id=hashlib.md5("Active Connections".encode("utf-8")).hexdigest(),
|
||||
),
|
||||
state_function=lambda ce: ce.samba["connections"],
|
||||
attributes_function=lambda ce: {"open_files": ce.samba["open_files"]},
|
||||
samba=samba,
|
||||
)
|
||||
sensorList.append(("samba_connections", sambaConnections.createSensor()))
|
||||
|
||||
tasks: list[asyncio.Task] = []
|
||||
|
||||
|
||||
async def publish_states() -> NoReturn:
|
||||
while True:
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityAutonomous):
|
||||
logging.info("Updating sensor %s", sensor[0])
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
|
||||
async def publish_idle_states() -> NoReturn:
|
||||
with open(args["hdidle_log"]) as pipe_hdidle:
|
||||
while True:
|
||||
line = pipe_hdidle.readline()
|
||||
if len(line) == 0:
|
||||
logging.error(f"Pipe Broken {args["hdidle_log"]}!")
|
||||
break
|
||||
# Parse line with ilde status
|
||||
# Aug 8 00:14:55 enterprise hd-idle[9958]: sda spindown
|
||||
# Aug 8 00:14:55 enterprise hd-idle[9958]: sdb spindown
|
||||
# Aug 8 00:14:56 enterprise hd-idle[9958]: sdc spindown
|
||||
# Aug 8 00:17:55 enterprise hd-idle[9958]: sdb spinup
|
||||
# Aug 8 00:28:55 enterprise hd-idle[9958]: sdb spindown
|
||||
disk, status = line.split(' ', maxsplit=1)
|
||||
logging.info("Disk %s change to status %s", disk, status.strip())
|
||||
devicePowerStatus[disk] = status.strip()
|
||||
logging.debug(devicePowerStatus)
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromHDIdle) and sensor[1].device.name == disk:
|
||||
logging.info("Updating sensor %s", sensor[0])
|
||||
if isinstance(sensor[1].sensor, BinarySensor):
|
||||
sensor[1].sensor.update_state(sensor[1].state_function(sensor[1]))
|
||||
elif isinstance(sensor[1].sensor, Sensor):
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
|
||||
|
||||
async def publish_device_states() -> NoReturn:
|
||||
while True:
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromDevice):
|
||||
logging.info(
|
||||
"Updating Device sensor %s (pw:%s)",
|
||||
sensor[0],
|
||||
devicePowerStatus.get(sensor[1].device.name),
|
||||
)
|
||||
|
||||
if devicePowerStatus.get(sensor[1].device.name) == "spindown":
|
||||
continue
|
||||
|
||||
sensor[1].device.update()
|
||||
if isinstance(sensor[1].sensor, BinarySensor):
|
||||
sensor[1].sensor.update_state(sensor[1].state_function(sensor[1]))
|
||||
elif isinstance(sensor[1].sensor, Sensor):
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1]))
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(5)
|
||||
|
||||
|
||||
async def publish_iostate_states() -> NoReturn:
|
||||
while True:
|
||||
|
||||
iostate: dict[str, sdiskio] = psutil.disk_io_counters(perdisk=True, nowrap=True)
|
||||
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromIoStat):
|
||||
logging.info("Updating Iostat sensor %s", sensor[0])
|
||||
sensor[1].addIostat(iostate)
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
async def publish_samba_states() -> NoReturn:
|
||||
while True:
|
||||
samba: dict[str, Any] = sambaMetricCollector()
|
||||
|
||||
for sensor in sensorList:
|
||||
if isinstance(sensor[1], ConfigEntityFromSamba):
|
||||
logging.info("Updating Samba sensor %s", sensor[0])
|
||||
sensor[1].samba = samba
|
||||
sensor[1].sensor.set_state(sensor[1].state_function(sensor[1])) # type: ignore
|
||||
if sensor[1].attributes_function is not None:
|
||||
sensor[1].sensor.set_attributes(
|
||||
sensor[1].attributes_function(sensor[1])
|
||||
)
|
||||
await asyncio.sleep(10)
|
||||
|
||||
|
||||
async def run() -> None:
|
||||
|
||||
def doneCallback(task):
|
||||
for sensor in sensorList:
|
||||
logging.info("Unpublish sensor %s", sensor[0])
|
||||
sensor[1].sensor.delete()
|
||||
|
||||
# Loop Status publish
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
if args["hdidle_log"] is not None:
|
||||
task = tg.create_task(publish_idle_states(), name="Read and Publish HD-IDLE states")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_states(), name="Publish States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_device_states(), name="Publish Device States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_iostate_states(), name="Publish IO States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
task = tg.create_task(publish_samba_states(), name="Publish Samba States")
|
||||
task.add_done_callback(doneCallback)
|
||||
tasks.append(task)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
async def ask_exit(signame):
|
||||
logging.warning("Signal %x. Unpublish %d sensors", signame, len(sensorList))
|
||||
|
||||
loop.remove_signal_handler(signame)
|
||||
|
||||
for task in tasks:
|
||||
try:
|
||||
task.cancel()
|
||||
finally:
|
||||
logging.warning(f"Task {task.get_name()} cancelled!")
|
||||
|
||||
for signame in ('SIGINT', 'SIGTERM', 'SIGHUP'):
|
||||
loop.add_signal_handler(getattr(signal, signame),
|
||||
lambda signame=signame: asyncio.create_task(ask_exit(signame)))
|
||||
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run())
|
403
sambanas/rootfs/usr/local/bin/poetry.lock
generated
Normal file
403
sambanas/rootfs/usr/local/bin/poetry.lock
generated
Normal file
@@ -0,0 +1,403 @@
|
||||
# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
description = "Reusable constraint types to use with typing.Annotated"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
|
||||
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chardet"
|
||||
version = "5.2.0"
|
||||
description = "Universal encoding detector for Python 3"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
|
||||
{file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diskinfo"
|
||||
version = "3.1.2"
|
||||
description = "Disk information Python library for Linux"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "diskinfo-3.1.2-py3-none-any.whl", hash = "sha256:2b8606462b5783d18188ff1a8b7c5094dbc455e8361418033ffe2a823aa3d4b7"},
|
||||
{file = "diskinfo-3.1.2.tar.gz", hash = "sha256:3f60a6f7b72dbf079c7f828540d38078e977aa5f578aa80a6e50b5860ffeaaa1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pySMART = ">=1.3.0"
|
||||
|
||||
[[package]]
|
||||
name = "gitlike-commands"
|
||||
version = "0.3.0"
|
||||
description = "Makes driver scripts that enable git-like commands so that foo bar will run foo-bar"
|
||||
optional = false
|
||||
python-versions = ">=3.9,<4.0"
|
||||
files = [
|
||||
{file = "gitlike_commands-0.3.0-py3-none-any.whl", hash = "sha256:c262f8f532639ec8558369bdc2cd904bd0b65638834ed333c42a51be69578f21"},
|
||||
{file = "gitlike_commands-0.3.0.tar.gz", hash = "sha256:72f4e65239cb6a4a2c614867c5f914b5d5994edd2863335515b543689b01ff70"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ha-mqtt-discoverable"
|
||||
version = "0.19.2"
|
||||
description = "Python library for creating MQTT entities compatible with Home Assistant"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.10.0"
|
||||
files = [
|
||||
{file = "ha_mqtt_discoverable-0.19.2-py3-none-any.whl", hash = "sha256:84725816a53d4e64f9d81cac6493c60dbd73899300c169b978fff9fdcbae2344"},
|
||||
{file = "ha_mqtt_discoverable-0.19.2.tar.gz", hash = "sha256:2c0facdfdff5573a4bae7ab40e9b66cc077e65445fb9d6f356e1c74ce00aa9d9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
gitlike-commands = ">=0.2.1,<0.4.0"
|
||||
paho-mqtt = "2.1.0"
|
||||
pyaml = "25.5.0"
|
||||
pydantic = "2.11.5"
|
||||
|
||||
[[package]]
|
||||
name = "humanfriendly"
|
||||
version = "10.0"
|
||||
description = "Human friendly output for text interfaces using Python"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
|
||||
{file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "humanize"
|
||||
version = "4.12.3"
|
||||
description = "Python humanize utilities"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "humanize-4.12.3-py3-none-any.whl", hash = "sha256:2cbf6370af06568fa6d2da77c86edb7886f3160ecd19ee1ffef07979efc597f6"},
|
||||
{file = "humanize-4.12.3.tar.gz", hash = "sha256:8430be3a615106fdfceb0b2c1b41c4c98c6b0fc5cc59663a5539b111dd325fb0"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["freezegun", "pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "paho-mqtt"
|
||||
version = "2.1.0"
|
||||
description = "MQTT version 5.0/3.1.1 client class"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "paho_mqtt-2.1.0-py3-none-any.whl", hash = "sha256:6db9ba9b34ed5bc6b6e3812718c7e06e2fd7444540df2455d2c51bd58808feee"},
|
||||
{file = "paho_mqtt-2.1.0.tar.gz", hash = "sha256:12d6e7511d4137555a3f6ea167ae846af2c7357b10bc6fa4f7c3968fc1723834"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
proxy = ["pysocks"]
|
||||
|
||||
[[package]]
|
||||
name = "psutil"
|
||||
version = "7.0.0"
|
||||
description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7."
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"},
|
||||
{file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"},
|
||||
{file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"},
|
||||
{file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"},
|
||||
{file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"},
|
||||
{file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"},
|
||||
{file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"]
|
||||
test = ["pytest", "pytest-xdist", "setuptools"]
|
||||
|
||||
[[package]]
|
||||
name = "pyaml"
|
||||
version = "25.5.0"
|
||||
description = "PyYAML-based module to produce a bit more pretty and readable YAML-serialized data"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyaml-25.5.0-py3-none-any.whl", hash = "sha256:b9e0c4e58a5e8003f8f18e802db49fd0563ada587209b13e429bdcbefa87d035"},
|
||||
{file = "pyaml-25.5.0.tar.gz", hash = "sha256:5799560c7b1c9daf35a7a4535f53e2c30323f74cbd7cb4f2e715b16dd681a58a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
PyYAML = "*"
|
||||
|
||||
[package.extras]
|
||||
anchors = ["unidecode"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.11.5"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pydantic-2.11.5-py3-none-any.whl", hash = "sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7"},
|
||||
{file = "pydantic-2.11.5.tar.gz", hash = "sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.6.0"
|
||||
pydantic-core = "2.33.2"
|
||||
typing-extensions = ">=4.12.2"
|
||||
typing-inspection = ">=0.4.0"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
timezone = ["tzdata"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.33.2"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"},
|
||||
{file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"},
|
||||
{file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"},
|
||||
{file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"},
|
||||
{file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"},
|
||||
{file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"},
|
||||
{file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"},
|
||||
{file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"},
|
||||
{file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"},
|
||||
{file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyreadline3"
|
||||
version = "3.5.4"
|
||||
description = "A python implementation of GNU readline."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
|
||||
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["build", "flake8", "mypy", "pytest", "twine"]
|
||||
|
||||
[[package]]
|
||||
name = "pysmart"
|
||||
version = "1.4.1"
|
||||
description = "Wrapper for smartctl (smartmontools)"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pySMART-1.4.1-py3-none-any.whl", hash = "sha256:8bb92d0bb579a073c60dca60cb69eea6516d7cf2673ad6d149d2a49e61432e5d"},
|
||||
{file = "pysmart-1.4.1.tar.gz", hash = "sha256:65700612477861acd83550c33a9430933017c93d91f66973ed409696b0327723"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
chardet = "*"
|
||||
humanfriendly = "*"
|
||||
|
||||
[package.extras]
|
||||
dev = ["coveralls", "pdoc", "pytest", "pytest-cov"]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.2"
|
||||
description = "YAML parser and emitter for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
|
||||
{file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
|
||||
{file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
|
||||
{file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
|
||||
{file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
|
||||
{file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
|
||||
{file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
|
||||
{file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.0"
|
||||
description = "Runtime typing introspection tools"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"},
|
||||
{file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.12.0"
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "13b19a408fb9cc0752b3e7d593791056598fe9ab78303fef118e37a7b6a3836f"
|
21
sambanas/rootfs/usr/local/bin/pyproject.toml
Normal file
21
sambanas/rootfs/usr/local/bin/pyproject.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[tool.poetry]
|
||||
name = "sambanas-util"
|
||||
version = "1.0.1"
|
||||
description = "Utility for SambaNas Addon"
|
||||
authors = ["dianlight <lucio.tarantino@gmail.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
pySMART = "^1.3.0"
|
||||
psutil = "^7.0.0"
|
||||
humanize = "^4.9.0"
|
||||
diskinfo = "^3.1.1"
|
||||
ha-mqtt-discoverable = "^0.19.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
155
sambanas/rootfs/usr/share/tempio/smb.gtpl
Normal file
155
sambanas/rootfs/usr/share/tempio/smb.gtpl
Normal file
@@ -0,0 +1,155 @@
|
||||
[global]
|
||||
{{ if .compatibility_mode }}
|
||||
client min protocol = NT1
|
||||
server min protocol = NT1
|
||||
{{ else }}
|
||||
server min protocol = SMB2_10
|
||||
client min protocol = SMB2_10
|
||||
{{ end }}
|
||||
|
||||
{{if .multi_channel }}
|
||||
server multi channel support = yes
|
||||
aio read size = 1
|
||||
aio write size = 1
|
||||
{{ end }}
|
||||
|
||||
dns proxy = yes
|
||||
|
||||
ea support = yes
|
||||
vfs objects = catia fruit streams_xattr{{ if .recyle_bin_enabled }} recycle{{ end }}
|
||||
fruit:aapl = yes
|
||||
fruit:model = MacSamba
|
||||
|
||||
fruit:resource = file
|
||||
fruit:veto_appledouble = no
|
||||
fruit:posix_rename = yes
|
||||
fruit:wipe_intentionally_left_blank_rfork = yes
|
||||
fruit:zero_file_id = yes
|
||||
fruit:delete_empty_adfiles = yes
|
||||
|
||||
# cherry pick from PR#167 to Test
|
||||
fruit:copyfile = yes
|
||||
fruit:nfs_aces = no
|
||||
|
||||
# Performance Enhancements for network
|
||||
socket options = TCP_NODELAY IPTOS_LOWDELAY
|
||||
min receivefile size = 16384
|
||||
getwd cache = yes
|
||||
aio read size = 1
|
||||
aio write size = 1
|
||||
# End PR#167
|
||||
|
||||
netbios name = {{ env "HOSTNAME" }}
|
||||
workgroup = {{ .workgroup }}
|
||||
server string = Samba NAS HomeAssistant config
|
||||
local master = {{ .local_master | ternary "yes" "no" }}
|
||||
multicast dns register = {{ if or .wsdd .wsdd2 }}no{{ else }}yes{{ end }}
|
||||
|
||||
security = user
|
||||
ntlm auth = yes
|
||||
idmap config * : backend = tdb
|
||||
idmap config * : range = 1000000-2000000
|
||||
|
||||
load printers = no
|
||||
disable spoolss = yes
|
||||
|
||||
{{ $log_level := dict "trace" "5" "debug" "4" "info" "3" "notice" "2" "warning" "1" "error" "1" "fatal" "1" -}}
|
||||
log level = {{ .log_level | default "warning" | get $log_level }}
|
||||
|
||||
bind interfaces only = {{ .bind_all_interfaces | default false | ternary "no" "yes" }}
|
||||
interfaces = 127.0.0.1 {{ .interfaces | join " " }} {{ .docker_interface | default " "}}
|
||||
hosts allow = 127.0.0.1 {{ .allow_hosts | join " " }} {{ .docker_net | default " " }}
|
||||
|
||||
mangled names = no
|
||||
dos charset = CP1253
|
||||
unix charset = UTF-8
|
||||
|
||||
{{ define "SHT" }}
|
||||
{{- $unsupported := list "vfat" "msdos" "f2fs" "fuseblk" "exfat" -}}
|
||||
{{- $rosupported := list "apfs"}}
|
||||
{{- $name := regexReplaceAll "[^A-Za-z0-9_/ ]" .share "_" | regexFind "[A-Za-z0-9_ ]+$" | upper -}}
|
||||
{{- $dinfo := get .shares $name | default dict -}}
|
||||
[{{- $name -}}]
|
||||
browseable = yes
|
||||
writeable = {{ has $dinfo.fs $rosupported | ternary "no" "yes" }}
|
||||
|
||||
# cherry pick from PR#167 to Test
|
||||
create mask = 0664
|
||||
force create mode = 0664
|
||||
directory mask = 0775
|
||||
force directory mode = 0775
|
||||
# End PR#167
|
||||
|
||||
path = /{{- if eq .share "config" }}homeassistant{{- else }}{{- .share }}{{- end }}
|
||||
valid users =_ha_mount_user_ {{ .users|default .username|join " " }} {{ .ro_users|join " " }}
|
||||
{{ if .ro_users }}
|
||||
read list = {{ .ro_users|join " " }}
|
||||
{{ end }}
|
||||
force user = root
|
||||
force group = root
|
||||
veto files = /{{ .veto_files | join "/" }}/
|
||||
delete veto files = {{ eq (len .veto_files) 0 | ternary "no" "yes" }}
|
||||
|
||||
# DEBUG: {{ toJson $dinfo }}|.share={{ .share }}|$name={{ $name }}|.shares={{ .shares }}|
|
||||
|
||||
{{if .recyle_bin_enabled }}
|
||||
recycle:repository = .recycle/%U
|
||||
recycle:keeptree = yes
|
||||
recycle:versions = yes
|
||||
recycle:touch = yes
|
||||
recycle:touch_mtime = no
|
||||
recycle:directory_mode = 0777
|
||||
#recycle:subdir_mode = 0700
|
||||
#recycle:exclude =
|
||||
#recycle:exclude_dir =
|
||||
#recycle:maxsize = 0
|
||||
{{ end }}
|
||||
|
||||
# TM:{{ if has $dinfo.fs $unsupported }}unsupported{{else}}{{ .timemachine }}{{ end }} US:{{ .users|default .username|join "," }} {{ .ro_users|join "," }}{{- if .medialibrary.enable }}{{ if .usage }} CL:{{ .usage }}{{ end }} FS:{{ $dinfo.fs | default "native" }} {{ if .recyle_bin_enabled }}RECYCLEBIN{{ end }} {{ end }}
|
||||
{{- if and .timemachine (has $dinfo.fs $unsupported | not ) }}
|
||||
vfs objects = catia fruit streams_xattr{{ if .recyle_bin_enabled }} recycle{{ end }}
|
||||
|
||||
# Time Machine Settings Ref: https://github.com/markthomas93/samba.apple.templates
|
||||
fruit:time machine = yes
|
||||
#fruit:time machine max size = SIZE [K|M|G|T|P]
|
||||
fruit:metadata = stream
|
||||
{{ end }}
|
||||
{{- if has $dinfo.fs $unsupported }}
|
||||
vfs objects = catia{{ if .recyle_bin_enabled }} recycle{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{- $dfdisk := list "config" "addons" "ssl" "share" "backup" "media" "addon_configs" }}
|
||||
{{- $disks := concat $dfdisk (compact .moredisks|default list) -}}
|
||||
{{- $root := . -}}
|
||||
{{- range $disk := $disks -}}
|
||||
{{- $acld := false -}}
|
||||
{{- range $dd := $root.acl -}}
|
||||
{{- $ndisk := $disk | regexFind "[A-Za-z0-9_]+$" -}}
|
||||
{{- if eq ($dd.share|upper) ($ndisk|upper) -}}
|
||||
{{- $def := deepCopy $dd }}
|
||||
{{- $acld = true -}}
|
||||
{{- if not $dd.disabled -}}
|
||||
{{- $_ := set $dd "share" $disk -}}
|
||||
{{- if has $disk $dfdisk -}}
|
||||
{{- $_ := set $def "timemachine" false -}}
|
||||
{{- $_ := set $def "usage" "" -}}
|
||||
{{- else -}}
|
||||
{{- $_ := set $def "timemachine" true -}}
|
||||
{{- $_ := set $def "usage" "media" -}}
|
||||
{{- end }}
|
||||
{{- template "SHT" deepCopy $root | mergeOverwrite $def $dd -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if not $acld -}}
|
||||
{{- $dd := dict "share" $disk "timemachine" true -}}
|
||||
{{- $_ := set $dd "usage" "media" -}}
|
||||
{{- if has $disk $dfdisk -}}
|
||||
{{- $_ := set $dd "timemachine" false -}}
|
||||
{{- $_ := set $dd "usage" "" -}}
|
||||
{{- end }}
|
||||
{{- template "SHT" (deepCopy $root | mergeOverwrite $dd) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
Reference in New Issue
Block a user