Skip to content

Commit

Permalink
rest of the plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
Morg42 committed Nov 24, 2023
1 parent 36d417a commit 39dbee8
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 213 deletions.
55 changes: 27 additions & 28 deletions roomba_980/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@
# along with SmartHome.py. If not, see <http://www.gnu.org/licenses/>.
#########################################################################

import logging
# TODO: das Modul ist im Sourcetree nicht vorhanden... woher soll das kommen?
from plugins.roomba_980.roomba import Roomba
from lib.model.smartplugin import SmartPlugin
from lib.item import Items


class ROOMBA_980(SmartPlugin):

ALLOW_MULTIINSTANCE = False
PLUGIN_VERSION = "1.0.1"
PLUGIN_VERSION = "1.0.2"

myroomba = None

def __init__(self, sh, adress=None, blid=None, roombaPassword=None, cycle=900):
self._address = adress
self._blid = blid
self._roombaPassword = roombaPassword
self._cycle = cycle
def __init__(self):
self._address = self.get_parameter_value('adress')
self._blid = self.get_parameter_value('blid')
self._roombaPassword = self.get_parameter_value('roombaPassword')
self._cycle = self.get_parameter_value('cycle')

self._status_batterie = None
self._status_items = {}
Expand All @@ -61,44 +61,43 @@ def run(self):
self.alive = True

def stop(self):
self.scheduler.remove('get_status')
self.scheduler_remove('get_status')
self.myroomba.disconnect()
self.alive = False

def __call__(self):
pass

def update_item(self, item, caller=None, source=None, dest=None):
if caller != __name__:
if caller != __name__ and self.alive:
self.logger.debug('item_update {} '.format(item))
if self.get_iattr_value(item.conf, 'roomba_980') == "start":
if item() == True:
self.send_command("start")
if item() is True:
self.send_command("start")
elif self.get_iattr_value(item.conf, 'roomba_980') == "stop":
if item() == True:
self.send_command("stop")
if item() is True:
self.send_command("stop")
elif self.get_iattr_value(item.conf, 'roomba_980') == "dock":
if item() == True:
self.send_command("dock")
if item() is True:
self.send_command("dock")

def get_status(self):
status = self.myroomba.master_state

for status_item in self._status_items:
if status_item == "status_batterie":
self._status_items[status_item](status['state']['reported']['batPct'],__name__)
elif status_item == "status_bin_full":
self._status_items[status_item](status['state']['reported']['bin']['full'],__name__)
elif status_item == "status_cleanMissionStatus_phase":
self._status_items[status_item](status['state']['reported']['cleanMissionStatus']['phase'],__name__)
elif status_item == "status_cleanMissionStatus_error":
self._status_items[status_item](status['state']['reported']['cleanMissionStatus']['error'],__name__)
if status_item == "status_batterie":
self._status_items[status_item](status['state']['reported']['batPct'], __name__)
elif status_item == "status_bin_full":
self._status_items[status_item](status['state']['reported']['bin']['full'], __name__)
elif status_item == "status_cleanMissionStatus_phase":
self._status_items[status_item](status['state']['reported']['cleanMissionStatus']['phase'], __name__)
elif status_item == "status_cleanMissionStatus_error":
self._status_items[status_item](status['state']['reported']['cleanMissionStatus']['error'], __name__)

self.logger.debug('Status update')

def send_command(self, command):
if self.myroomba != None:
self.myroomba.send_command(command)
self.logger.debug('send command: {} to Roomba'.format(command))

if self.myroomba is not None:
self.myroomba.send_command(command)
self.logger.debug('send command: {} to Roomba'.format(command))

18 changes: 9 additions & 9 deletions roomba_980/plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,46 @@ plugin:
en: 'integration of the iRobot Roomba vacuum cleaner series 900'
maintainer: 'Zapfen83'
tester: '?'
state: ready
state: development
keywords: irobot roomba # keywords, where applicable
# documentation: https://github.com/smarthomeNG/plugins/blob/develop/mqtt/README.md # url of documentation (wiki) page
# support: https://knx-user-forum.de/forum/supportforen/smarthome-py

# Following entries are for Smart-Plugins:
version: 1.0.1 # Plugin version
sh_minversion: 1.5 # minimum shNG version to use this plugin
version: 1.0.2 # Plugin version
sh_minversion: 1.6 # minimum shNG version to use this plugin
# sh_maxversion: # maximum shNG version to use this plugin (leave empty if latest)
multi_instance: False
restartable: unknown
multi_instance: false
restartable: true
classname: ROOMBA_980 # class containing the plugin

parameters:
# Definition of parameters to be configured in etc/plugin.yaml

adress:
type: str
default: True
default: true
description:
de: "Die IP Adresse des roomba Staubsaugers"
en: "The IP address of the roomba vacuum cleaner"

blid:
type: str
default: True
default: true
description:
de: "Die blid des roomba Staubsaugers -> kann mit der getpassword.py ausgelesen werden"
en: "The blid of the roomba vacuum cleaner -> use getpassword.py to get it"

roombaPassword:
type: str
default: True
default: true
description:
de: "Das Passwort des roomba Staubsaugers -> kann mit der getpassword.py ausgelesen werden"
en: "The password of the roomba vacuum cleaner -> use getpassword.py to get it"

cycle:
type: num
default: False
default: false
description:
de: "update des items alle x Sekunden, default wert 900"
en: "update the state item every x secounds, default is 900"
Expand Down
81 changes: 41 additions & 40 deletions sma/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,29 @@
#
# SMA-Plugin for SmartHomeNG. https://github.com/smarthomeNG//
#
# License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
# http://creativecommons.org/licenses/by-nc-sa/3.0/
# License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)
# http://creativecommons.org/licenses/by-nc-sa/3.0/
#
# You are free:
# to Share — to copy, distribute and transmit the work
# to Remix — to adapt the work
# Under the following conditions:
# Attribution:
# You must attribute the work in the manner specified by the author or licensor
# (but not in any way that suggests that they endorse you or your use of the work).
# Noncommercial:
# You may not use this work for commercial purposes.
# Share Alike:
# If you alter, transform, or build upon this work, you may distribute the resulting work
# only under the same or similar license to this one.
# You are free:
# to Share — to copy, distribute and transmit the work
# to Remix — to adapt the work
# Under the following conditions:
# Attribution:
# You must attribute the work in the manner specified by the author or licensor
# (but not in any way that suggests that they endorse you or your use of the work).
# Noncommercial:
# You may not use this work for commercial purposes.
# Share Alike:
# If you alter, transform, or build upon this work, you may distribute the resulting work
# only under the same or similar license to this one.
#
# DISCLAIMER:
# A user of this plugin acknowledges that he or she is receiving this
# software on an "as is" basis and the user is not relying on the accuracy
# or functionality of the software for any purpose. The user further
# acknowledges that any use of this software will be at his own risk
# and the copyright owner accepts no responsibility whatsoever arising from
# the use or application of the software.
# A user of this plugin acknowledges that he or she is receiving this
# software on an "as is" basis and the user is not relying on the accuracy
# or functionality of the software for any purpose. The user further
# acknowledges that any use of this software will be at his own risk
# and the copyright owner accepts no responsibility whatsoever arising from
# the use or application of the software.
#########################################################################

import logging
Expand All @@ -42,7 +42,6 @@
import socket
from datetime import datetime
from dateutil import tz
import itertools

from lib.model.smartplugin import SmartPlugin

Expand Down Expand Up @@ -185,19 +184,19 @@

class SMA(SmartPlugin):
ALLOW_MULTIINSTANCE = False
PLUGIN_VERSION = "1.3.1"
PLUGIN_VERSION = "1.3.2"

def __init__(self, smarthome, bt_addr, password="0000", update_cycle="60", allowed_timedelta="10"):
def __init__(self):
# TODO: self._own_bt_addr setzen
self.logger = logging.getLogger(__name__)
self._sh = smarthome
self._update_cycle = int(update_cycle)
self._inv_bt_addr = self.get_parameter_value('bt_addr')
self._inv_password = self.get_parameter_value('password')
self._update_cycle = self.get_parameter_value('update_cycle')
self._allowed_timedelta = self.get_parameter_value('allowed_timedelta')
self._fields = {}
self._requests = []
self._cmd_lock = threading.Lock()
self._reply_lock = threading.Condition()
self._inv_bt_addr = bt_addr
self._inv_password = password
self._allowed_timedelta = int(allowed_timedelta)
self._inv_last_read_timestamp_utc = 0
self._inv_serial = 0
self._own_bt_addr_le = bytearray(BCAST_ADDR)
Expand All @@ -209,7 +208,7 @@ def __init__(self, smarthome, bt_addr, password="0000", update_cycle="60", allow
raise Exception("Python socket module does not support Bluetooth - see README.md how to install")

def _update_values(self):
#logger.warning("sma: signal strength = {}%%".format(self._inv_get_bt_signal_strength()))
# logger.warning("sma: signal strength = {}%%".format(self._inv_get_bt_signal_strength()))
self._cmd_lock.acquire()
try:
for request in self._requests:
Expand All @@ -224,7 +223,7 @@ def _update_values(self):
self._reply_lock.release()
if ('LAST_UPDATE' in self._fields) and not (self._inv_last_read_timestamp_utc == 0):
self._inv_last_read_datetime = datetime.fromtimestamp(self._inv_last_read_timestamp_utc, tz.tzlocal())
#self._inv_last_read_str = self._inv_last_read_datetime.strftime("%d.%m.%Y %H:%M:%S")
# self._inv_last_read_str = self._inv_last_read_datetime.strftime("%d.%m.%Y %H:%M:%S")
self._inv_last_read_str = self._inv_last_read_datetime.strftime("%d.%m. %H:%M ")
for item in self._fields['LAST_UPDATE']['items']:
item(self._inv_last_read_str, 'SMA', self._inv_serial)
Expand All @@ -241,7 +240,7 @@ def run(self):
self._plugin_active = self._plugin_active_item()
# "or self._is_connected" ensures the connection will be closed before terminating
while self.alive or self._is_connected:
#self.logger.warning("sma: state self._is_connected = {} / self._plugin_active = {} / self.alive = {}".format(self._is_connected, self._plugin_active, self.alive))
# self.logger.warning("sma: state self._is_connected = {} / self._plugin_active = {} / self.alive = {}".format(self._is_connected, self._plugin_active, self.alive))

# connect to inverter if active but not connected
if self._plugin_active and not self._is_connected:
Expand Down Expand Up @@ -318,7 +317,7 @@ def run(self):
if not self.alive:
break
if msg is None:
#self.logger.debug("sma: no msg...")
# self.logger.debug("sma: no msg...")
continue
if len(msg) >= 60:
i = 41
Expand All @@ -331,16 +330,16 @@ def run(self):
if lri not in lris:
self.logger.info("sma: unknown lri={:#06x} / cls={:#02x} / dataType={:#02x} - trying to continue".format(lri, cls, dataType))
if (dataType == 0x00) or (dataType == 0x40):
i += 28
i += 28
elif (dataType == 0x08) or (dataType == 0x10):
i += 40
i += 40
else:
self.logger.error("sma: rx - unknown datatype {:#02x}".format(dataType))
raise
continue
else:
timestamp_utc = int.from_bytes(msg[i + 4:i + 8], byteorder='little')
value = eval(lri_evals[lris[lri][0]], dict(msg=msg,i=i,attribute_to_text=attribute_to_text))
value = eval(lri_evals[lris[lri][0]], dict(msg=msg, i=i, attribute_to_text=attribute_to_text))
i += lris[lri][1]
self.logger.debug("sma: lri={:#06x} / cls={:#02x} / timestamp={} / value={}".format(lri, cls, timestamp_utc, value))
if full_id in self._fields:
Expand Down Expand Up @@ -477,6 +476,7 @@ def _recv_smanet2_msg(self, no_timeout_warning=False):
# remove escape characters
i = 0
while True:
# TODO: if this works - fine, seems not to be standard Python 3?
if smanet2_msg[i] == 0x7d:
smanet2_msg[i + 1] ^= 0x20
del(smanet2_msg[i])
Expand All @@ -493,6 +493,7 @@ def _recv_smanet2_msg(self, no_timeout_warning=False):

def _recv_smanet1_msg_with_cmdcode(self, cmdcodes_expected=[0x0001]):
retries = 3
msg = None
while self.alive:
retries -= 1
if retries == 0:
Expand Down Expand Up @@ -522,15 +523,15 @@ def _send_msg(self, msg):
# set length fields
msg[1:3] = len(msg).to_bytes(2, byteorder='little')
msg[3] = msg[1] ^ msg[2] ^ 0x7e
#print("tx: len={} / data=[{}]".format(len(msg), ' '.join(['0x%02x' % b for b in msg])))
# print("tx: len={} / data=[{}]".format(len(msg), ' '.join(['0x%02x' % b for b in msg])))
self._btsocket.send(msg)

def _calc_crc16(self, msg):
crc = 0xFFFF
for i in msg:
crc = (crc >> 8) ^ FCSTAB[(crc ^ i) & 0xFF]
crc ^= 0xFFFF
#print("crc16 = {:x}".format(crc))
# print("crc16 = {:x}".format(crc))
return crc

def _inv_connect(self):
Expand Down Expand Up @@ -653,7 +654,7 @@ def _inv_send_request(self, request_set):
msg += SMANET2_HDR + bytes([0x09, 0xA0]) + BCAST_ADDR + bytes([0x00, 0x00]) + self._inv_bt_addr_le + bytes([0x00] + [0x00] + [0, 0, 0, 0]) + (self._send_count | 0x8000).to_bytes(2, byteorder='little')
msg += request_set[0].to_bytes(4, byteorder='little') + request_set[1].to_bytes(4, byteorder='little') + request_set[2].to_bytes(4, byteorder='little')
# send msg to inverter
#self.logger.debug("sma: requesting {:#06x}-{:#06x}...".format(request_set[1], request_set[2]))
# self.logger.debug("sma: requesting {:#06x}-{:#06x}...".format(request_set[1], request_set[2]))
self._send_msg(msg)

def _inv_set_time(self):
Expand All @@ -666,7 +667,7 @@ def _inv_set_time(self):
msg += SMANET2_HDR + bytes([0x10, 0xA0]) + BCAST_ADDR + bytes([0x00, 0x00]) + self._inv_bt_addr_le + bytes([0x00] + [0x00] + [0, 0, 0, 0]) + (self._send_count | 0x8000).to_bytes(2, byteorder='little')
msg += int(0xF000020A).to_bytes(4, byteorder='little') + int(0x00236D00).to_bytes(4, byteorder='little') + int(0x00236D00).to_bytes(4, byteorder='little') + int(0x00236D00).to_bytes(4, byteorder='little')
local_time = int(time.time()).to_bytes(4, byteorder='little')
msg += local_time + local_time + local_time + round((datetime.now()-datetime.utcnow()).total_seconds()).to_bytes(4, byteorder='little') + local_time + bytes([0x01, 0x00, 0x00, 0x00])
msg += local_time + local_time + local_time + round((datetime.now() - datetime.utcnow()).total_seconds()).to_bytes(4, byteorder='little') + local_time + bytes([0x01, 0x00, 0x00, 0x00])
# msg += local_time + local_time + local_time + time.localtime().tm_gmtoff.to_bytes(4, byteorder='little') + local_time + bytes([0x01, 0x00, 0x00, 0x00])
# send msg to inverter
self._send_msg(msg)
self._send_msg(msg)
Loading

0 comments on commit 39dbee8

Please sign in to comment.