Implement rename and delete

This commit introduces the ability to rename or delete a light.
There is also a special icon for unreachable lights now.
pull/17/head
Micke Nordin 3 years ago
parent 9c1f5c4e17
commit 7cfe8049fc
Signed by: micke
GPG Key ID: 014B273D614BE877

@ -21,10 +21,15 @@ cd tinge
Requires a recent Python3 and pip3, most likely python >= 3.7. It is only tested with 3.9 on PostmarketOS on the PinePhone and on Debian Bullseye though. Requires a recent Python3 and pip3, most likely python >= 3.7. It is only tested with 3.9 on PostmarketOS on the PinePhone and on Debian Bullseye though.
## Screenshots ## Screenshots
![Discover Bridge View](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_16h18m26s_grim.png) ![Discover Bridge View](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot1.png)
![All Bridge View](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_14h48m15s_grim.png) ![All Bridge View](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot2.png)
![All Group View](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_14h48m24s_grim.png) ![All Group View](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot3.png)
![Single Group View, with Bed Light Off](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_14h48m30s_grim.png) ![Single Group View, with Some Lights Off, and Roof light unreachable](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot4.png)
![Single Light Off](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_14h48m34s_grim.png) ![Single Light View, with Bed Lamp Off](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot5.png)
![Single Light On](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_14h48m37s_grim.png) ![Single Light View, with Bed Lamp On](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot6.png)
![Single Group View, with Bed Light On](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/20210506_14h48m48s_grim.png) ![Single Group View, with Bed Lamp On](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot7.png)
![Rename Bed lamp](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot8.png)
![Single Light View, with Bed Lamp renamed to Table lamp](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot9.png)
![Single Group View, with Bed Lamp renamed to Table lamp](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot10.png)
![Single Light View, with Table lamp Delete modal](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot11.png)
![Single Group View, with Table lamp Deleted](https://code.smolnet.org/micke/tinge/raw/branch/master/screenshots/scrot12.png)

@ -38,6 +38,7 @@ class Hui(wx.Frame):
super().__init__(*args, **kw) super().__init__(*args, **kw)
self.m_on_icon: str = '' self.m_on_icon: str = ''
self.m_off_icon: str = '' self.m_off_icon: str = ''
self.m_unreachable_icon: str = ''
self.m_tinge: Tinge = Tinge() self.m_tinge: Tinge = Tinge()
self.m_bridges: list[HueBridge] = self.m_tinge.get_bridges() self.m_bridges: list[HueBridge] = self.m_tinge.get_bridges()
self.cur_bridge: Union[None, HueBridge] = None self.cur_bridge: Union[None, HueBridge] = None
@ -114,6 +115,8 @@ class Hui(wx.Frame):
icon: str = self.m_off_icon icon: str = self.m_off_icon
if light.is_on(): if light.is_on():
icon = self.m_on_icon icon = self.m_on_icon
elif not light.is_reachable():
icon = self.m_unreachable_icon
toggle_btn: wx.Button = wx.Button(self.pnl, label=icon) toggle_btn: wx.Button = wx.Button(self.pnl, label=icon)
inner_sizer.Add(toggle_btn, 1, wx.EXPAND) inner_sizer.Add(toggle_btn, 1, wx.EXPAND)
self.Bind(wx.EVT_BUTTON, self.Bind(wx.EVT_BUTTON,
@ -145,6 +148,8 @@ class Hui(wx.Frame):
icon: str = self.m_off_icon icon: str = self.m_off_icon
if is_on: if is_on:
icon = self.m_on_icon icon = self.m_on_icon
elif not light.is_reachable():
icon = self.m_unreachable_icon
toggle_btn: wx.Button = wx.Button(self.pnl, label=icon) toggle_btn: wx.Button = wx.Button(self.pnl, label=icon)
self.sizer.Add(toggle_btn, 0, wx.EXPAND) self.sizer.Add(toggle_btn, 0, wx.EXPAND)
self.Bind(wx.EVT_BUTTON, self.Bind(wx.EVT_BUTTON,
@ -187,6 +192,30 @@ class Hui(wx.Frame):
self.sizer.Add(e_slider, 0, wx.EXPAND) self.sizer.Add(e_slider, 0, wx.EXPAND)
self.Bind(wx.EVT_SCROLL, self.Bind(wx.EVT_SCROLL,
lambda event: self.set_saturation(event, light.get_id()), e_slider) lambda event: self.set_saturation(event, light.get_id()), e_slider)
rename_btn: wx.Button = wx.Button(self.pnl, label="Rename")
self.sizer.Add(rename_btn, 0, wx.EXPAND)
self.Bind(wx.EVT_BUTTON,
lambda event, mlightid=lightid: self.rename_light_and_goto_light(mlightid),
rename_btn)
delete_btn: wx.Button = wx.Button(self.pnl, label="Delete")
self.sizer.Add(delete_btn, 0, wx.EXPAND)
self.Bind(wx.EVT_BUTTON,
lambda event, mlightid=lightid: self.delete_light_and_goto_group(mlightid),
delete_btn)
def delete_light_and_goto_group(self, lightid):
"""Combo call back for delete and goto group
Args:
lightid (int): The light id of the light to delete
"""
if self.get_ok_cancel_answer_from_modal("Are you sure you want to delete this light?"):
light: HueLight = self.cur_bridge.get_light_by_id(lightid)
light.delete()
self.cur_bridge.remove_light(light)
self.add_lights(self.cur_group.get_lights())
else:
self.add_single_light(lightid)
def discover_new_bridges(self): def discover_new_bridges(self):
"""Call back for button that is displayed if no bridges were found """Call back for button that is displayed if no bridges were found
@ -194,6 +223,34 @@ class Hui(wx.Frame):
self.m_tinge.discover_new_bridges() self.m_tinge.discover_new_bridges()
self.add_bridges() self.add_bridges()
def get_ok_cancel_answer_from_modal(self, message: str) -> bool:
"""Display a message dialog and return ok or cancel
Args:
message (str): The message to display
Returns:
bool: The response from the user
"""
with wx.MessageDialog(self.pnl, message, style=wx.OK | wx.CANCEL | wx.CANCEL_DEFAULT) as dlg:
return dlg.ShowModal() == wx.ID_OK
def get_text_answer_from_modal(self, message: str, cap: str, val: str = "") -> str:
"""Display a text entry and return the content
Args:
message (str): The message to display
cap (str): The caption to display
val (str, optional): The default value to display, defaults to the empty string
Returns:
str: The response from the user
"""
with wx.TextEntryDialog(self.pnl, message, caption=cap, value=val) as dlg:
dlg.ShowModal()
answer: str = dlg.GetValue()
return answer
def goto_bridge(self, bridge: HueBridge): def goto_bridge(self, bridge: HueBridge):
"""Call back for a bridge button """Call back for a bridge button
@ -217,6 +274,17 @@ class Hui(wx.Frame):
self.cur_group = group self.cur_group = group
self.add_lights(group.get_lights()) self.add_lights(group.get_lights())
def rename_light_and_goto_light(self, lightid):
"""Combo call back to rename a light and display that light again
Args:
lightid ([type]): The light id of the light to rename/display
"""
newname: str = self.get_text_answer_from_modal("Set new name", "New name:")
if newname:
self.cur_bridge.get_light_by_id(lightid).rename(newname)
self.add_single_light(lightid)
def set_brightness(self, event: wx.ScrollEvent, lightid: int): def set_brightness(self, event: wx.ScrollEvent, lightid: int):
"""Call back for brightness slider """Call back for brightness slider
@ -283,7 +351,7 @@ class Hui(wx.Frame):
"""Combo call back for toggle and goto group """Combo call back for toggle and goto group
Args: Args:
lightid (int): The light id oof the light to toggle lightid (int): The light id of the light to toggle
lights (list[HueLight]): The lights to display after toggle lights (list[HueLight]): The lights to display after toggle
""" """
self.cur_bridge.get_light_by_id(lightid).toggle() self.cur_bridge.get_light_by_id(lightid).toggle()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@ -190,3 +190,14 @@ class HueBridge:
str: The username str: The username
""" """
return self.m_username return self.m_username
def remove_light(self, light: HueLight):
"""Remove a light from all groups and self
Args:
light (HueLight): The light to remove
"""
for group in self.m_groups:
group.remove_light(light)
self.m_lights.remove(light)

@ -142,6 +142,12 @@ class HueGroup:
on = True on = True
return on return on
def remove_light(self, light: HueLight):
"""Remove a light
"""
if light in self.m_lights:
self.m_lights.remove(light)
def toggle(self): def toggle(self):
"""Toggle all lights of the group """Toggle all lights of the group
""" """

@ -297,6 +297,14 @@ class HueLight:
""" """
return self.get_sat() != -1 return self.get_sat() != -1
def delete(self):
"""Delete the light
"""
method: str = "DELETE"
path = "{}/lights/{}".format(self.m_parent_bridge_user, self.get_id())
make_request(self.m_parent_bridge_ip, path, method)
def get_brightness(self) -> int: def get_brightness(self) -> int:
"""Get currrent brightness """Get currrent brightness
@ -362,6 +370,18 @@ class HueLight:
""" """
return self.get_state().is_reachable() return self.get_state().is_reachable()
def rename(self, name):
"""Set the name of the light
Args:
name (str): The new name for the light
"""
method: str = "PUT"
payload = '{{"name":"{0}"}}'.format(name)
path = "{}/lights/{}".format(self.m_parent_bridge_user, self.get_id())
make_request(self.m_parent_bridge_ip, path, method, payload)
self.update_state()
def set_brightness(self, bri: int): def set_brightness(self, bri: int):
"""Set the brightness of the light """Set the brightness of the light
@ -431,3 +451,4 @@ class HueLight:
path: str = "{}/lights/{}".format(self.m_parent_bridge_user, self.m_id) path: str = "{}/lights/{}".format(self.m_parent_bridge_user, self.m_id)
response = make_request(self.m_parent_bridge_ip, path) response = make_request(self.m_parent_bridge_ip, path)
self.m_state = HueLight.State(json.loads(response.text)['state']) self.m_state = HueLight.State(json.loads(response.text)['state'])
self.m_name = json.loads(response.text)['name']

Loading…
Cancel
Save