Commit f93022a0 authored by Benjamin Mummery's avatar Benjamin Mummery 💻

update battery display for 2 batteries

At present raspberry-dataserver/BatteryLLI.py uses popen to run
upower as a shell command and parses the output. This should be
replaced by the upower python script (I would have done this, but I
can't compile upower on the Pi to test it)

raspberry-dataserver/CommsCommon.py is modified to add new parameters to
BatteryFormat (bat1_percent and bat2_percent, both ints). All other
parameters in BatteryFormat are unchanged.
parent 6abc4d31
......@@ -15,8 +15,9 @@ class BatteryHandler(PayloadHandler):
self.__battery_status = {
"on_mains_power":False,
"on_battery_power":False,
"battery_percent":0,
"electrical_problem": "ERROR ELEC."
"battery_percent_1":0,
"battery_percent_2":0,
"electrical_problem": "ERR"
}
def active_payload(self, *args, **kwargs) -> int:
......@@ -39,15 +40,20 @@ class BatteryHandler(PayloadHandler):
logging.debug("Keyerror in battery payload: 'bat'")
try:
new_status["battery_percent"] = self.compute_battery_percent(battery_data)
new_status["battery_percent_1"] = int(battery_data["bat1_percent"])
except KeyError:
logging.debug("Keyerror in battery payload: 'bat85'")
logging.debug("Keyerror in battery payload: 'bat1_percent'")
try:
new_status["battery_percent_2"] = int(battery_data["bat2_percent"])
except KeyError:
logging.debug("Keyerror in battery payload: 'bat2_percent'")
try:
if battery_data["prob_elec"] == 0:
new_status["electrical_problem"] = None
else:
new_status["electrical_problem"] = "ERROR ELEC."
new_status["electrical_problem"] = "ERR"
except KeyError:
logging.debug("Keyerror in battery payload: 'prob_elec'")
......@@ -56,7 +62,7 @@ class BatteryHandler(PayloadHandler):
# If there is conflicting information w.r.t. power source, report a problem
new_status["on_mains_power"] = False
new_status["on_battery_power"] = False
new_status["electrical_problem"] = "ERROR ELEC."
new_status["electrical_problem"] = "ERR"
self.__battery_status = new_status
......@@ -67,22 +73,22 @@ class BatteryHandler(PayloadHandler):
self.UpdateBatteryDisplay.emit(self.__battery_status)
return 0
def compute_battery_percent(self, battery_data: dict) -> float:
"""
Determine the current battery percentage from the information in battery_data.
As of 17/03/21 battery payloads only contain enough information to
determine if the battery is above or below 85% battery life.
Unless provided with specific information to the contrary, assume that the
battery is on 0% so that we should never overestimate how much remains.
"""
if battery_data["bat85"] == 1:
return 85.0
elif battery_data["bat85"] == 0:
return 0.0
else:
raise TypeError(
"Battery Percentage (entry 'bat85' in the battery payload) is not 1 or 2."
)
# def compute_battery_percent(self, battery_data: dict) -> float:
# """
# Determine the current battery percentage from the information in battery_data.
# As of 17/03/21 battery payloads only contain enough information to
# determine if the battery is above or below 85% battery life.
# Unless provided with specific information to the contrary, assume that the
# battery is on 0% so that we should never overestimate how much remains.
# """
# if battery_data["bat85"] == 1:
# return 85.0
# elif battery_data["bat85"] == 0:
# return 0.0
# else:
# raise TypeError(
# "Battery Percentage (entry 'bat85' in the battery payload) is not 1 or 2."
# )
......@@ -186,10 +186,10 @@ class Layout:
# Define Sizes
f_mode = 0.15
f_battery = 0.2
f_lock = 0.1
f_battery = 0.235
f_lock = 0.01
f_localisation = 0.1
f_alarm = 0.2
f_alarm = 0.115
f_personal = 1 - (f_mode + f_battery + f_lock + f_localisation + f_alarm)
mode_display_width = int(self.screen_width * f_mode)
......
......@@ -58,6 +58,7 @@ class AlarmControlWidget(QtWidgets.QWidget):
"background-color: "
+ NativeUI.colors["button_background_enabled"].name()
+ "; border:none;"
+ "color:" + NativeUI.colors["page_foreground"].name() + ";"
)
self.iconStack.addWidget(self.onSpeakers)
self.offSpeakers = QtWidgets.QPushButton()
......@@ -66,6 +67,7 @@ class AlarmControlWidget(QtWidgets.QWidget):
"background-color: "
+ NativeUI.colors["button_background_enabled"].name()
+ "; border:none;"
+ "color:" + NativeUI.colors["page_foreground"].name() + ";"
)
self.iconStack.addWidget(self.offSpeakers)
hlayout.addWidget(self.iconStack)
......@@ -83,19 +85,19 @@ class AlarmControlWidget(QtWidgets.QWidget):
pixmap.setMask(mask)
self.onSpeakers.setIcon(QtGui.QIcon(pixmap))
self.__icon_path = os.path.join(NativeUI.iconpath, "bell-regular.png")
pixmap = QtGui.QPixmap(self.__icon_path)
mask = pixmap.mask()
pixmap.fill(NativeUI.colors["plot_flow"])
pixmap.setMask(mask)
self.offSpeakers.setIcon(QtGui.QIcon(pixmap))
self.timeLabel = QtWidgets.QLabel("")
self.timeLabel.setFont(NativeUI.value_font)
self.timeLabel.setStyleSheet(
"color:" + NativeUI.colors["page_foreground"].name() + ";"
)
hlayout.addWidget(self.timeLabel)
# self.__icon_path = os.path.join(NativeUI.iconpath, "bell-regular.png")
# pixmap = QtGui.QPixmap(self.__icon_path)
# mask = pixmap.mask()
# pixmap.fill(NativeUI.colors["plot_flow"])
# pixmap.setMask(mask)
# self.offSpeakers.setIcon(QtGui.QIcon(pixmap))
# self.timeLabel = QtWidgets.QLabel("")
self.offSpeakers.setFont(NativeUI.value_font)
# self.timeLabel.setStyleSheet(
# "color:" + NativeUI.colors["page_foreground"].name() + ";"
# )
# hlayout.addWidget(self.timeLabel)
self.setLayout(hlayout)
self.timer = QtCore.QTimer()
......@@ -107,7 +109,7 @@ class AlarmControlWidget(QtWidgets.QWidget):
def mute_timer(self):
self.remaining_mute_time += -1
self.timeLabel.setText(str(self.remaining_mute_time))
self.offSpeakers.setText(str(self.remaining_mute_time))
if self.remaining_mute_time == 0:
self.unmute_pressed()
......@@ -122,7 +124,7 @@ class AlarmControlWidget(QtWidgets.QWidget):
def unmute_pressed(self):
self.timer.stop()
self.remaining_mute_time = 120
self.timeLabel.setText("")
self.offSpeakers.setText("120")
self.buttonPushed(self.volState)
self.iconStack.setCurrentWidget(self.onSpeakers)
self.NativeUI.q_send_cmd("MUTE_ALARM", "FALSE")
......@@ -157,7 +159,11 @@ class AlarmControlWidget(QtWidgets.QWidget):
logging.debug('didnt work')
def set_size(self, x: int, y: int, spacing=10) -> int:
if x < 2.2*y:
x = 2.2*y
self.setFixedSize(x, y)
self.offSpeakers.setFixedSize(1.1*y,y)
self.onSpeakers.setFixedSize(1.1*y,y)
return 0
def localise_text(self, text: dict) -> int:
......
......@@ -29,9 +29,11 @@ class BatteryDisplayWidget(QtWidgets.QWidget):
self.NativeUI = NativeUI
layout = QtWidgets.QHBoxLayout(self)
self.icon_display = BatteryIcon(NativeUI)
self.text_display = BatteryText(NativeUI)
self.widgets = [self.icon_display, self.text_display]
self.icon_display_1 = BatteryIcon(NativeUI, "battery_percent_1")
self.text_display_1 = BatteryText(NativeUI, "battery_percent_1")
self.icon_display_2 = BatteryIcon(NativeUI, "battery_percent_2")
self.text_display_2 = BatteryText(NativeUI, "battery_percent_2")
self.widgets = [self.icon_display_1, self.text_display_1, self.icon_display_2, self.text_display_2]
for widget in self.widgets:
layout.addWidget(widget, alignment=QtCore.Qt.AlignRight)
......@@ -80,9 +82,11 @@ class BatteryDisplayWidget(QtWidgets.QWidget):
assert isinstance(x, int)
assert isinstance(y, int)
self.setFixedSize(x, y)
self.icon_display.set_size(y, y)
self.text_display.set_size(x - y, y)
self.setFixedSize(2*(int(x/2)-y), y)
self.icon_display_1.set_size(y, y)
self.text_display_1.set_size(int(x/2) - y, y)
self.icon_display_2.set_size(y, y)
self.text_display_2.set_size(int(x/2) - y, y)
return 0
def setFont(self, font: QtGui.QFont) -> int:
......@@ -90,7 +94,8 @@ class BatteryDisplayWidget(QtWidgets.QWidget):
Overrides the existing setFont method in order to propogate the change to
subwidgets.
"""
self.text_display.setFont(font)
self.text_display_1.setFont(font)
self.text_display_2.setFont(font)
return 0
def localise_text(self, text: dict) -> int:
......@@ -103,10 +108,11 @@ class BatteryDisplayWidget(QtWidgets.QWidget):
class BatteryText(QtWidgets.QLabel):
""""""
def __init__(self, NativeUI, *args, **kwargs):
def __init__(self, NativeUI, key, *args, **kwargs):
super().__init__("", *args, **kwargs)
self.__size = (0, 0)
self.key = key
self.setStyleSheet(
"background-color:" + NativeUI.colors["page_background"].name() + ";"
......@@ -125,7 +131,7 @@ class BatteryText(QtWidgets.QLabel):
self.__apply_temp_size(0, self.__size[1])
return 0
self.setText(str(status["battery_percent"]) + " %")
self.setText(str(status[self.key]) + " %")
return 0
def set_size(self, x: int, y: int) -> int:
......@@ -161,9 +167,9 @@ class BatteryIcon(QtWidgets.QPushButton):
Widget to display the current battery icon
"""
def __init__(self, NativeUI, *args, **kwargs):
def __init__(self, NativeUI, key, *args, **kwargs):
super().__init__("", *args, **kwargs)
self.key = key
self.NativeUI = NativeUI
self.__icon_list = self.__make_icon_list()
self.__mains_icon = os.path.join(self.NativeUI.iconpath, "plug-solid.png")
......@@ -191,7 +197,7 @@ class BatteryIcon(QtWidgets.QPushButton):
self.setIcon(
QtGui.QIcon(
self.__icon_list[self.__get_range_index(status["battery_percent"])]
self.__icon_list[self.__get_range_index(status[self.key])]
)
)
return 0
......@@ -215,7 +221,7 @@ class BatteryIcon(QtWidgets.QPushButton):
"""
if self.__icon_list is None:
self.__icon_list = self.__make_icon_list()
n_icons = len(self.__icon_list)
n_icons = len(self.__icon_list)-1
percent_per_icon = 100.0 / n_icons
if percent_per_icon < zero_point:
zero_point = percent_per_icon
......@@ -239,6 +245,7 @@ class BatteryIcon(QtWidgets.QPushButton):
"battery-quarter-solid.png",
"battery-half-solid.png",
"battery-three-quarters-solid.png",
"battery-full-solid.png",
]
icon_list = [os.path.join(self.NativeUI.iconpath, icon) for icon in icon_list]
return icon_list
......
......@@ -71,6 +71,7 @@ class BatteryLLI:
async def main(self) -> None:
while True:
await asyncio.sleep(self._timeout)
print(1)
payload = BatteryFormat(dummy=self._dummy)
try:
for pin in self._pins:
......
......@@ -26,6 +26,7 @@
import asyncio
import logging
import copy
import os
from CommsCommon import BatteryFormat
# Set up logging
logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s')
......@@ -72,9 +73,78 @@ class BatteryLLI:
while True:
await asyncio.sleep(self._timeout)
payload = BatteryFormat(dummy=self._dummy)
# Get output from upower
# TODO: change this to use the upower python module
upower_out_list = os.popen("./../upower/upower22/src/upower_22").read().split('\n')
upower_out_dict = {}
for l in upower_out_list:
tmp = l.split("=")
if len(tmp) != 2:
logging.debug("Skipping upower output line: %s" % l)
continue
key = tmp[0].lstrip().rstrip()
value = tmp[1].lstrip().rstrip()
if key in upower_out_dict:
key += "_2"
upower_out_dict[key] = value
del upower_out_list
# set bat value
payload_dict = {}
try:
if upower_out_dict["AC Status"] == "No Plug":
payload_dict["ok"] = 1
payload_dict["bat"] = 0
else:
payload_dict["ok"] = 0
payload_dict["bat"] = 1
except KeyError:
logging.warning("No key 'AC Status' in upower output")
payload_dict["ok"] = 0
payload_dict["bat"] = 0
# set bat85 value
try:
payload_dict["bat1_percent"] = int(
upower_out_dict["RemainPercent"].rstrip("%")
)
except KeyError:
logging.warning("No key 'RemainPercent' in upower output")
payload_dict["bat1_percent"] = 0
try:
payload_dict["bat2_percent"] = int(
upower_out_dict["RemainPercent_2"].rstrip("%")
)
except KeyError:
logging.warning("No key 'RemainPercent_2' in upower output")
payload_dict["bat2_percent"] = 0
total_batt = payload_dict["bat1_percent"] + payload_dict["bat2_percent"]
if total_batt >= 85:
payload_dict["bat85"] = 1
else:
payload_dict["bat85"] = 0
# dummy_payload_dict = {
# "bat":1,
# "ok":0,
# "alarm":0,
# "rdy2buf":0,
# "bat85":1,
# "prob_elec":0,
# "dummy":True,
# "bat1_percent":13,
# "bat2_percent":93,
# }
# Construct payload
for key in payload_dict:
setattr(payload, key, payload_dict[key])
try:
for pin in self._pins:
setattr(payload, pin, gpio.input(self._pins[pin]))
self.queue.put_nowait(payload)
except asyncio.queues.QueueFull:
try:
......
......@@ -873,7 +873,7 @@ class LogMsgFormat(PayloadFormat):
# BATTERY data payload
# =======================================
@dataclass
class BatteryFormat(PayloadFormat):
class OldBatteryFormat(PayloadFormat):
_dataStruct = Struct("<BIBbbbbbbb")
payload_type: PAYLOAD_TYPE = PAYLOAD_TYPE.BATTERY
......@@ -905,6 +905,43 @@ class BatteryFormat(PayloadFormat):
self.payload_type = PAYLOAD_TYPE(tmp_payload_type)
self._byteArray = byteArray
@dataclass
class BatteryFormat(PayloadFormat):
_dataStruct = Struct("<BIBbbbbbbbbb")
payload_type: PAYLOAD_TYPE = PAYLOAD_TYPE.BATTERY
bat: int = 0
ok: int = 0
alarm: int = 0
rdy2buf: int = 0
bat85: int = 0
prob_elec: int = 0
dummy: int = 0
bat1_percent: int = 0
bat2_percent: int = 0
# fill the struct from a byteArray,
def fromByteArray(self, byteArray):
tmp_payload_type = 0
(
self.version,
self.timestamp,
tmp_payload_type,
self.bat,
self.ok,
self.alarm,
self.rdy2buf,
self.bat85,
self.prob_elec,
self.dummy,
self.bat1_percent,
self.bat2_percent,
) = self._dataStruct.unpack(byteArray)
self.checkVersion()
self.payload_type = PAYLOAD_TYPE(tmp_payload_type)
self._byteArray = byteArray
# =======================================
# cmd type payload
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment