mirror of
https://github.com/meshtastic/python.git
synced 2026-03-04 14:56:24 -05:00
Add support for NRF PPK2 power testing board.
This commit is contained in:
@@ -21,7 +21,7 @@ from meshtastic import channel_pb2, config_pb2, portnums_pb2, remote_hardware, B
|
||||
from meshtastic.version import get_active_version
|
||||
from meshtastic.ble_interface import BLEInterface
|
||||
from meshtastic.mesh_interface import MeshInterface
|
||||
from meshtastic.powermon import RidenPowerSupply
|
||||
from meshtastic.powermon import RidenPowerSupply, PPK2PowerSupply
|
||||
from meshtastic.slog import StructuredLogger
|
||||
|
||||
def onReceive(packet, interface):
|
||||
@@ -1093,6 +1093,16 @@ def common():
|
||||
meter = None # assume no power meter
|
||||
if args.power_riden:
|
||||
meter = RidenPowerSupply(args.power_riden)
|
||||
elif args.power_ppk2:
|
||||
meter = PPK2PowerSupply()
|
||||
|
||||
if meter and args.power_voltage:
|
||||
v = float(args.power_voltage)
|
||||
if v < 1.0 or v >5.0:
|
||||
meshtastic.util.our_exit("Voltage must be between 1.0 and 5.0")
|
||||
logging.info(f"Setting power supply to {v} volts")
|
||||
meter.v = v
|
||||
meter.powerOn()
|
||||
|
||||
StructuredLogger(client, meter)
|
||||
|
||||
@@ -1521,6 +1531,11 @@ def initParser():
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
group.add_argument(
|
||||
"--power-voltage",
|
||||
help="Set the specified voltage on the power-supply. Be VERY careful, you can burn things up.",
|
||||
)
|
||||
|
||||
group.add_argument(
|
||||
"--power-stress",
|
||||
help="Perform power monitor stress testing, to capture a power consumption profile for the device (also requires --power-mon)",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"""Support for logging from power meters/supplies."""
|
||||
|
||||
from .riden import *
|
||||
from .power_supply import PowerMeter, PowerSupply, PowerError
|
||||
from .riden import RidenPowerSupply
|
||||
from .ppk2 import PPK2PowerSupply
|
||||
49
meshtastic/powermon/power_supply.py
Normal file
49
meshtastic/powermon/power_supply.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""code logging power consumption of meshtastic devices."""
|
||||
|
||||
import math
|
||||
from datetime import datetime
|
||||
|
||||
class PowerError(Exception):
|
||||
"""An exception class for powermon errors"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
super().__init__(self.message)
|
||||
|
||||
|
||||
class PowerMeter:
|
||||
"""Abstract class for power meters."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the PowerMeter object."""
|
||||
self.prevPowerTime = datetime.now()
|
||||
self.prevWattHour = self._getRawWattHour()
|
||||
|
||||
def getWatts(self) -> float:
|
||||
"""Get the total amount of power that has been consumed since the previous call of this method"""
|
||||
now = datetime.now()
|
||||
nowWattHour = self._getRawWattHour()
|
||||
watts = (
|
||||
(nowWattHour - self.prevWattHour)
|
||||
/ (now - self.prevPowerTime).total_seconds()
|
||||
* 3600
|
||||
)
|
||||
self.prevPowerTime = now
|
||||
self.prevWattHour = nowWattHour
|
||||
return watts
|
||||
|
||||
def _getRawWattHour(self) -> float:
|
||||
"""Get the current watt-hour reading (without any offset correction)."""
|
||||
return math.nan
|
||||
|
||||
|
||||
|
||||
class PowerSupply(PowerMeter):
|
||||
"""Abstract class for power supplies."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the PowerSupply object."""
|
||||
super().__init__()
|
||||
self.v = 3.3
|
||||
|
||||
def powerOn(self):
|
||||
"""Turn on the power supply (using the voltage set in self.v)."""
|
||||
47
meshtastic/powermon/ppk2.py
Normal file
47
meshtastic/powermon/ppk2.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""code logging power consumption of meshtastic devices."""
|
||||
|
||||
import logging
|
||||
from typing import *
|
||||
|
||||
from ppk2_api import ppk2_api
|
||||
from .power_supply import PowerSupply, PowerError
|
||||
|
||||
|
||||
|
||||
class PPK2PowerSupply(PowerSupply):
|
||||
"""Interface for talking with the NRF PPK2 high-resolution micro-power supply.
|
||||
Power Profiler Kit II is what you should google to find it for purchase.
|
||||
"""
|
||||
|
||||
def __init__(self, portName: Optional[str] = None):
|
||||
"""Initialize the PowerSupply object.
|
||||
|
||||
portName (str, optional): The port name of the power supply. Defaults to "/dev/ttyACM0".
|
||||
"""
|
||||
if not portName:
|
||||
devs = ppk2_api.PPK2_API.list_devices()
|
||||
if not devs or len(devs) == 0:
|
||||
raise PowerError("No PPK2 devices found")
|
||||
elif len(devs) > 1:
|
||||
raise PowerError("Multiple PPK2 devices found, please specify the portName")
|
||||
else:
|
||||
portName = devs[0]
|
||||
|
||||
self.r = r = ppk2_api.PPK2_MP(portName) # serial port will be different for you
|
||||
r.get_modifiers()
|
||||
|
||||
logging.info("Connected to PPK2 power supply")
|
||||
|
||||
super().__init__() # we call this late so that the port is already open and _getRawWattHour callback works
|
||||
|
||||
def powerOn(self):
|
||||
"""Power on the supply, with reasonable defaults for meshtastic devices."""
|
||||
self.r.use_source_meter() # set source meter mode
|
||||
self.r.set_source_voltage(self.v * 1000) # set source voltage in mV
|
||||
self.r.toggle_DUT_power("ON")
|
||||
self.r.start_measuring() # start measuring
|
||||
|
||||
|
||||
def _getRawWattHour(self) -> float:
|
||||
"""Get the current watt-hour reading."""
|
||||
return 4 # FIXME
|
||||
@@ -1,52 +1,14 @@
|
||||
"""code logging power consumption of meshtastic devices."""
|
||||
|
||||
import logging
|
||||
import math
|
||||
from datetime import datetime
|
||||
|
||||
from riden import Riden
|
||||
|
||||
class PowerMeter:
|
||||
"""Abstract class for power meters."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the PowerMeter object."""
|
||||
self.prevPowerTime = datetime.now()
|
||||
self.prevWattHour = self._getRawWattHour()
|
||||
|
||||
def getWatts(self) -> float:
|
||||
"""Get the total amount of power that has been consumed since the previous call of this method"""
|
||||
now = datetime.now()
|
||||
nowWattHour = self._getRawWattHour()
|
||||
watts = (
|
||||
(nowWattHour - self.prevWattHour)
|
||||
/ (now - self.prevPowerTime).total_seconds()
|
||||
* 3600
|
||||
)
|
||||
self.prevPowerTime = now
|
||||
self.prevWattHour = nowWattHour
|
||||
return watts
|
||||
|
||||
def _getRawWattHour(self) -> float:
|
||||
"""Get the current watt-hour reading (without any offset correction)."""
|
||||
return math.nan
|
||||
|
||||
|
||||
|
||||
class PowerSupply(PowerMeter):
|
||||
"""Abstract class for power supplies."""
|
||||
|
||||
def setMaxCurrent(self, i: float):
|
||||
"""Set the maximum current the supply will provide."""
|
||||
|
||||
def powerOn(self, v: float):
|
||||
"""Turn on the power supply."""
|
||||
|
||||
|
||||
from .power_supply import PowerSupply
|
||||
|
||||
class RidenPowerSupply(PowerSupply):
|
||||
"""Interface for talking to programmable bench-top power supplies.
|
||||
Currently only the Riden supplies are supported (RD6006 tested)
|
||||
"""Interface for talking to Riden programmable bench-top power supplies.
|
||||
Only RD6006 tested but others should be similar.
|
||||
"""
|
||||
|
||||
def __init__(self, portName: str = "/dev/ttyUSB0"):
|
||||
@@ -65,9 +27,9 @@ class RidenPowerSupply(PowerSupply):
|
||||
"""Set the maximum current the supply will provide."""
|
||||
self.r.set_i_set(i)
|
||||
|
||||
def powerOn(self, v: float):
|
||||
def powerOn(self):
|
||||
"""Power on the supply, with reasonable defaults for meshtastic devices."""
|
||||
self.r.set_v_set(v) # my WM1110 devboard header is directly connected to the 3.3V rail
|
||||
self.r.set_v_set(self.v) # my WM1110 devboard header is directly connected to the 3.3V rail
|
||||
self.r.set_output(1)
|
||||
|
||||
def _getRawWattHour(self) -> float:
|
||||
|
||||
Reference in New Issue
Block a user