Skip to content

Commit

Permalink
Merge pull request #9 from grimmpp/feature-branch
Browse files Browse the repository at this point in the history
F2SR14 Support
  • Loading branch information
grimmpp authored Feb 18, 2024
2 parents dc95e14 + 1246570 commit 3f022a7
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 31 deletions.
4 changes: 4 additions & 0 deletions changes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## v0.1.7 F2SR14 Support
* Support for F4SR14 added
* Update Button added

## v0.1.6 Sensor Values are evaluated
* Sensor values are displayed in command line
* Sponsor button added
Expand Down
1 change: 1 addition & 0 deletions eo_man/controller/app_bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class AppBusEventType(Enum):
SET_DATA_TABLE_FILTER = 13 # applies data filter to data table
ADDED_DATA_TABLE_FILTER = 14 # adds data filter to application data
REMOVED_DATA_TABLE_FILTER = 15 # remove data filter from application data
RELOAD = 16

class AppBus():

Expand Down
35 changes: 34 additions & 1 deletion eo_man/data/app_info.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import os
import requests

class ApplicationInfo():

app_info:dict[str:str]=None
pypi_info_latest_versino:dict=None
pypi_info_current_version:dict=None

@classmethod
def get_app_info(cls, filename:str=None):
Expand Down Expand Up @@ -39,9 +42,31 @@ def get_app_info(cls, filename:str=None):
app_info['license'] = l.split(':',1)[1].strip()
elif l.startswith('Requires-Python:'):
app_info['requires-python'] = l.split(':',1)[1].strip()

# get latest version
cls.pypi_info_latest_versino = cls._get_info_from_pypi()
app_info['lastest_available_version'] = cls.pypi_info_latest_versino.get('info', {}).get('version', None)
# get current/installed version
if app_info['version'] is not None and app_info['version'] != '':
cls.pypi_info_current_version = cls._get_info_from_pypi(app_info['version'])

return app_info

@classmethod
def _get_info_from_pypi(cls, version:str=''):
if version is not None and version != '':
if not version.startswith('/') and not version.endswith('/'):
version = version + '/'

url = f"https://pypi.org/pypi/eo-man/{version}json"

response = requests.get(url)
if response.status_code == 200:
return response.json()

return {}


@classmethod
def get_app_info_as_str(cls, separator:str='\n', prefix:str='') -> str:
result = ''
Expand Down Expand Up @@ -75,4 +100,12 @@ def get_license(cls) -> str:

@classmethod
def get_requires_python(cls) -> str:
return cls.get_app_info().get('requires-python', 'unknown')
return cls.get_app_info().get('requires-python', 'unknown')

@classmethod
def get_lastest_available_version(cls) -> str:
return cls.get_app_info().get('lastest_available_version', 'unknown')

@classmethod
def is_version_up_to_date(cls) -> bool:
return cls.pypi_info_current_version['info']['version'] == cls.pypi_info_latest_versino['info']['version']
1 change: 1 addition & 0 deletions eo_man/data/data_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
{'hw-type': 'FSR14_1x', CONF_EEP: 'M5-38-08', 'sender_eep': 'A5-38-08', CONF_TYPE: Platform.LIGHT, 'PCT14-function-group': 2, 'PCT14-key-function': 51, 'description': 'Eltako relay', 'address_count': 1},
{'hw-type': 'FSR14_x2', CONF_EEP: 'M5-38-08', 'sender_eep': 'A5-38-08', CONF_TYPE: Platform.LIGHT, 'PCT14-function-group': 2, 'PCT14-key-function': 51, 'description': 'Eltako relay', 'address_count': 2},
{'hw-type': 'FSR14_4x', CONF_EEP: 'M5-38-08', 'sender_eep': 'A5-38-08', CONF_TYPE: Platform.LIGHT, 'PCT14-function-group': 2, 'PCT14-key-function': 51, 'description': 'Eltako relay', 'address_count': 4},
{'hw-type': 'F4SR14_LED', CONF_EEP: 'M5-38-08', 'sender_eep': 'A5-38-08', CONF_TYPE: Platform.LIGHT, 'PCT14-function-group': 2, 'PCT14-key-function': 51, 'description': 'Eltako relay', 'address_count': 4},

{'hw-type': 'FSB14', CONF_EEP: 'G5-3F-7F', 'sender_eep': 'H5-3F-7F', CONF_TYPE: Platform.COVER, 'PCT14-function-group': 2, 'PCT14-key-function': 31, 'description': 'Eltako cover', 'address_count': 2},

Expand Down
39 changes: 22 additions & 17 deletions eo_man/data/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,35 +117,40 @@ async def async_get_bus_device_by_natvice_bus_object(cls, device: BusObject, fam
if bd.dev_size > 1:
bd.name += f" ({bd.channel}/{bd.dev_size})"

info:dict = find_device_info_by_device_type(bd.device_type)
Device.set_suggest_ha_config(bd)

return bd

@classmethod
def set_suggest_ha_config(cls, device):
id = int.from_bytes( AddressExpression.parse(device.address)[0], 'big')
info:dict = find_device_info_by_device_type(device.device_type)
if info is not None:
bd.use_in_ha = True
bd.ha_platform = info[CONF_TYPE]
bd.eep = info.get(CONF_EEP, None)
device.use_in_ha = True
device.ha_platform = info[CONF_TYPE]
device.eep = info.get(CONF_EEP, None)

if info.get('sender_eep', None):
bd.additional_fields['sender'] = {
device.additional_fields['sender'] = {
CONF_ID: a2s( SENDER_BASE_ID + id ),
CONF_EEP: info.get('sender_eep')
}

if info[CONF_TYPE] == Platform.COVER:
bd.additional_fields[CONF_DEVICE_CLASS] = 'shutter'
bd.additional_fields[CONF_TIME_CLOSES] = 25
bd.additional_fields[CONF_TIME_OPENS] = 25
device.additional_fields[CONF_DEVICE_CLASS] = 'shutter'
device.additional_fields[CONF_TIME_CLOSES] = 25
device.additional_fields[CONF_TIME_OPENS] = 25

if info[CONF_TYPE] == Platform.CLIMATE:
bd.additional_fields[CONF_TEMPERATURE_UNIT] = f"'{UnitOfTemperature.KELVIN}'"
bd.additional_fields[CONF_MIN_TARGET_TEMPERATURE] = 16
bd.additional_fields[CONF_MAX_TARGET_TEMPERATURE] = 25
thermostat = BusObjectHelper.find_sensor(bd.memory_entries, device.address, channel, in_func_group=1)
device.additional_fields[CONF_TEMPERATURE_UNIT] = f"'{UnitOfTemperature.KELVIN}'"
device.additional_fields[CONF_MIN_TARGET_TEMPERATURE] = 16
device.additional_fields[CONF_MAX_TARGET_TEMPERATURE] = 25
thermostat = BusObjectHelper.find_sensor(device.memory_entries, device.address, device.channel, in_func_group=1)
if thermostat:
bd.additional_fields[CONF_ROOM_THERMOSTAT] = {}
bd.additional_fields[CONF_ROOM_THERMOSTAT][CONF_ID] = b2s(thermostat.sensor_id)
bd.additional_fields[CONF_ROOM_THERMOSTAT][CONF_EEP] = A5_10_06.eep_string #TODO: derive EEP from switch/sensor function
device.additional_fields[CONF_ROOM_THERMOSTAT] = {}
device.additional_fields[CONF_ROOM_THERMOSTAT][CONF_ID] = b2s(thermostat.sensor_id)
device.additional_fields[CONF_ROOM_THERMOSTAT][CONF_EEP] = A5_10_06.eep_string #TODO: derive EEP from switch/sensor function
#TODO: cooling_mode

return bd

@classmethod
def get_decentralized_device_by_telegram(cls, msg: RPSMessage):
Expand Down
17 changes: 9 additions & 8 deletions eo_man/data/ha_config_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@ def generate_ha_config(self, device_list:list[Device]) -> str:
out += f" {CONF_DEVICES}:\n"

for platform in ha_platforms:
out += f" {platform}:\n"
for _d in [d for d in devices if d.ha_platform == platform]:
device:Device = _d
# devices
if device.base_id == fam14.external_id:
out += self.config_section_from_device_to_string(device, True, 0) + "\n\n"
elif 'sensor' in platform:
out += self.config_section_from_device_to_string(device, True, 0) + "\n\n"
if platform != '':
out += f" {platform}:\n"
for _d in [d for d in devices if d.ha_platform == platform]:
device:Device = _d
# devices
if device.base_id == fam14.external_id:
out += self.config_section_from_device_to_string(device, True, 0) + "\n\n"
elif 'sensor' in platform:
out += self.config_section_from_device_to_string(device, True, 0) + "\n\n"
# logs
out += "logger:\n"
out += " default: info\n"
Expand Down
Binary file added eo_man/icons/Software-update-available.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 8 additions & 1 deletion eo_man/icons/image_gallary.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import os
from PIL import Image, ImageTk

# icon list
# https://commons.wikimedia.org/wiki/Comparison_of_icon_sets

class ImageGallery():

@classmethod
Expand Down Expand Up @@ -44,4 +47,8 @@ def get_about_icon(cls, size:tuple[int:int]=(32,32)) -> ImageTk.PhotoImage:

@classmethod
def get_github_icon(cls, size:tuple[int:int]=(32,32)) -> ImageTk.PhotoImage:
return ImageGallery.get_image("github_icon.png", size)
return ImageGallery.get_image("github_icon.png", size)

@classmethod
def get_software_update_available_icon(cls, size:tuple[int:int]=(32,32)) -> ImageTk.PhotoImage:
return ImageGallery.get_image("Software-update-available.png", size)
21 changes: 21 additions & 0 deletions eo_man/view/menu_presenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
from tkinter import *
from tkinter import filedialog
import logging
from tkinter import messagebox
import webbrowser

from ..controller.app_bus import AppBus, AppBusEventType

from ..data.device import Device
from ..data.data_manager import DataManager
from ..data.ha_config_generator import HomeAssistantConfigurationGenerator

Expand Down Expand Up @@ -72,6 +74,12 @@ def __init__(self, main: Tk, app_bus: AppBus, data_manager: DataManager):
accelerator="ALT+F")


ha_menu = Menu(menu_bar, tearoff=False)
menu_bar.add_cascade(label="Home Assistant", menu=ha_menu)
ha_menu.add_command(label="Reset to suggested HA properties.",
command=self.reset_to_suggested_ha_properties)


help_menu = Menu(menu_bar, tearoff=False)
menu_bar.add_cascade(label="Help", menu=help_menu)

Expand Down Expand Up @@ -224,8 +232,21 @@ def export_ha_config(self, save_as:bool=False):
self.app_bus.fire_event(AppBusEventType.LOG_MESSAGE, {'msg': msg, 'log-level': 'ERROR', 'color': 'red'})
logging.exception(msg, exc_info=True)


def reset_to_suggested_ha_properties(self):
yes = messagebox.askyesno("Reset to suggested HA properties.", "Do you want to reset Home Assistant relevant properties of all devices to initial values?")
if yes:
for d in self.data_manager.devices.values():
Device.set_suggest_ha_config(d)
if d.is_bus_device():
self.app_bus.fire_event(AppBusEventType.UPDATE_DEVICE_REPRESENTATION, d)
else:
self.app_bus.fire_event(AppBusEventType.UPDATE_SENSOR_REPRESENTATION, d)

def open_eo_man_repo(self):
webbrowser.open_new(r"https://github.com/grimmpp/enocean-device-manager")

def open_eo_man_documentation(self):
webbrowser.open_new(r"https://github.com/grimmpp/enocean-device-manager/tree/main/docs")


27 changes: 26 additions & 1 deletion eo_man/view/tool_bar.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import threading
import tkinter as tk
import os
from tkinter import *
from tkinter import messagebox
from PIL import Image, ImageTk
from idlelib.tooltip import Hovertip
import webbrowser
import subprocess

from eo_man import LOGGER

from .donation_button import DonationButton
from .menu_presenter import MenuPresenter
from ..icons.image_gallary import ImageGallery
from ..data.app_info import ApplicationInfo as AppInfo


class ToolBar():
Expand All @@ -32,10 +38,29 @@ def __init__(self, main: Tk, menu_presenter:MenuPresenter, row:int):
b = self._create_img_button(f, "GitHub: EnOcean Device Manager Documentation", ImageGallery.get_help_icon(), menu_presenter.open_eo_man_documentation)
b.pack(side=RIGHT, padx=(0,2), pady=2)

if not AppInfo.is_version_up_to_date():
new_v = AppInfo.get_lastest_available_version()
b = self._create_img_button(f, f"New Software Version 'v{new_v}' is available.", ImageGallery.get_software_update_available_icon(), self.show_how_to_update)
b.pack(side=RIGHT, padx=(0,2), pady=2)


def _create_img_button(self, f:Frame, tooltip:str, image:ImageTk.PhotoImage, command) -> Button:
b = Button(f, image=image, relief=GROOVE, cursor="hand2", command=command)
Hovertip(b,tooltip,300)
b.image = image
b.pack(side=LEFT, padx=(2,0), pady=2)
return b


def show_how_to_update(self):
base_path = os.environ.get('VIRTUAL_ENV', '')
if base_path != '':
base_path = os.path.join(base_path, 'Scripts')

new_version = AppInfo.get_lastest_available_version()

msg = f"A new version 'v{new_version}' of 'EnOcean Device Manager' is available. \n\n"
msg += f"You can update this application by entering \n"
msg += f"'{os.path.join(base_path, 'pip')}' install eo_man --upgrade'\n"
msg += f"into the command line."

messagebox.showinfo("Update Available", msg)
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import os
from setuptools import setup, find_packages
from distutils.core import setup
import shutil
import re



base_dir = os.path.dirname(__file__)
Expand All @@ -24,7 +23,7 @@

setup(
name='eo_man',
version='0.1.6',
version='0.1.7',
package_dir={'eo_man':"eo_man"},
# packages=find_packages("./eo-man"),
#package_data={'': ['*.png']},
Expand Down

0 comments on commit 3f022a7

Please sign in to comment.