From fb51fdaa24f335e0537bfda865ddfae007301b88 Mon Sep 17 00:00:00 2001
From: Morg42 <43153739+Morg42@users.noreply.github.com>
Date: Fri, 24 Nov 2023 13:38:20 +0100
Subject: [PATCH 1/6] modified some plugins for parameter checks,
restartability and code cleanness
---
comfoair/__init__.py | 196 ++++++++++++-------------
comfoair/plugin.yaml | 17 ++-
helios/__init__.py | 318 ++++++++++++++++++++--------------------
helios/plugin.yaml | 11 +-
intercom_2n/__init__.py | 153 +++++++++----------
intercom_2n/plugin.yaml | 13 +-
jvcproj/__init__.py | 35 ++---
jvcproj/plugin.yaml | 8 +-
kostal/__init__.py | 112 ++++++--------
kostal/plugin.yaml | 10 +-
luxtronic2/__init__.py | 88 ++++-------
luxtronic2/plugin.yaml | 13 +-
plex/__init__.py | 44 +++---
plex/plugin.yaml | 8 +-
rcswitch/__init__.py | 189 ++++++++++++------------
rcswitch/plugin.yaml | 6 +-
16 files changed, 599 insertions(+), 622 deletions(-)
diff --git a/comfoair/__init__.py b/comfoair/__init__.py
index 1bfcf970f..5196fff66 100755
--- a/comfoair/__init__.py
+++ b/comfoair/__init__.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+# !/usr/bin/env python
#########################################################################
# Copyright 2013 Stefan Kals
#########################################################################
@@ -22,7 +22,6 @@
import socket
import time
import serial
-import re
import threading
from . import commands
@@ -32,33 +31,30 @@
class ComfoAir(SmartPlugin):
ALLOW_MULTIINSTANCE = False
- PLUGIN_VERSION = '1.3.0'
+ PLUGIN_VERSION = '1.3.1'
- def __init__(self, smarthome, host=None, port=0, serialport=None, kwltype='comfoair350'):
+ def __init__(self):
self.logger = logging.getLogger('ComfoAir')
self.connected = False
- self._sh = smarthome
self._params = {}
self._init_cmds = []
self._cyclic_cmds = {}
self._lock = threading.Lock()
- self._host = host
- self._port = int(port)
- self._serialport = serialport
+ self._host = self.get_parameter_value('host')
+ self._port = self.get_parameter_value('port')
+ self._serialport = self.get_parameter_value('serialport')
+ self._kwltype = self.get_parameter_value('kwltype')
self._connection_attempts = 0
self._connection_errorlog = 60
self._initread = False
- # automatically (re)connect
- smarthome.connections.monitor(self)
-
# Load controlset and commandset
- if kwltype in commands.controlset and kwltype in commands.commandset:
- self._controlset = commands.controlset[kwltype]
- self._commandset = commands.commandset[kwltype]
- self.log_info('Loaded commands for KWL type \'{}\''.format(kwltype))
+ if self._kwltype in commands.controlset and self._kwltype in commands.commandset:
+ self._controlset = commands.controlset[self._kwltype]
+ self._commandset = commands.commandset[self._kwltype]
+ self.log_info('Loaded commands for KWL type \'{}\''.format(self._kwltype))
else:
- self.log_err('Commands for KWL type \'{}\' could not be found!'.format(kwltype))
+ self.log_err('Commands for KWL type \'{}\' could not be found!'.format(self._kwltype))
return None
# Remember packet config
@@ -69,13 +65,13 @@ def __init__(self, smarthome, host=None, port=0, serialport=None, kwltype='comfo
self._reponsecommandinc = self._controlset['ResponseCommandIncrement']
self._commandlength = 2
self._checksumlength = 1
-
+
def connect(self):
- if self._serialport is not None:
+ if self._serialport:
self.connect_serial()
else:
self.connect_tcp()
-
+
def connect_tcp(self):
self._lock.acquire()
try:
@@ -94,12 +90,12 @@ def connect_tcp(self):
self.log_info('connected to {}:{}'.format(self._host, self._port))
self._connection_attempts = 0
self._lock.release()
-
+
def connect_serial(self):
self._lock.acquire()
try:
self._serialconnection = serial.Serial(
- self._serialport, 9600, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, timeout=2)
+ self._serialport, 9600, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, timeout=2)
except Exception as e:
self._connection_attempts -= 1
if self._connection_attempts <= 0:
@@ -118,8 +114,8 @@ def disconnect(self):
self.disconnect_serial()
else:
self.disconnect_tcp()
-
- def disconnect_tcp(self):
+
+ def disconnect_tcp(self):
self.connected = False
try:
self._sock.shutdown(socket.SHUT_RDWR)
@@ -130,54 +126,54 @@ def disconnect_tcp(self):
except:
pass
- def disconnect_serial(self):
+ def disconnect_serial(self):
self.connected = False
try:
self._serialconnection.close()
self._serialconnection = None
except:
pass
-
+
def send_bytes(self, packet):
if self._serialport is not None:
self.send_bytes_serial(packet)
else:
self.send_bytes_tcp(packet)
-
+
def send_bytes_tcp(self, packet):
self._sock.sendall(packet)
def send_bytes_serial(self, packet):
self._serialconnection.write(packet)
-
+
def read_bytes(self, length):
if self._serialport is not None:
return self.read_bytes_serial(length)
else:
return self.read_bytes_tcp(length)
-
+
def read_bytes_tcp(self, length):
return self._sock.recv(length)
def read_bytes_serial(self, length):
return self._serialconnection.read(length)
-
+
def parse_item(self, item):
# Process the read config
if self.has_iattr(item.conf, 'comfoair_read'):
commandname = self.get_iattr_value(item.conf, 'comfoair_read')
- if (commandname == None or commandname not in self._commandset):
+ if (commandname is None or commandname not in self._commandset):
self.log_err('Item {} contains invalid read command \'{}\'!'.format(item, commandname))
return None
-
+
# Remember the read config to later update this item if the configured response comes in
self.log_info('Item {} reads by using command \'{}\'.'.format(item, commandname))
commandconf = self._commandset[commandname]
commandcode = commandconf['Command']
- if not commandcode in self._params:
+ if commandcode not in self._params:
self._params[commandcode] = {'commandname': [commandname], 'items': [item]}
- elif not item in self._params[commandcode]['items']:
+ elif item not in self._params[commandcode]['items']:
self._params[commandcode]['commandname'].append(commandname)
self._params[commandcode]['items'].append(item)
@@ -185,7 +181,7 @@ def parse_item(self, item):
if (self.has_iattr(item.conf, 'comfoair_init') and self.get_iattr_value(item.conf, 'comfoair_init') == 'true'):
self.log_info('Item {} is initialized on startup.'.format(item))
# Only add the item to the initial commands if it is not cyclic. Cyclic commands get called on init because this is the first cycle...
- if not commandcode in self._init_cmds and not self.has_iattr(item.conf, 'comfoair_read_cycle'):
+ if commandcode not in self._init_cmds and not self.has_iattr(item.conf, 'comfoair_read_cycle'):
self._init_cmds.append(commandcode)
# Allow items to be cyclically updated
@@ -193,7 +189,7 @@ def parse_item(self, item):
cycle = int(self.get_iattr_value(item.conf, 'comfoair_read_cycle'))
self.log_info('Item {} should read cyclic every {} seconds.'.format(item, cycle))
- if not commandcode in self._cyclic_cmds:
+ if commandcode not in self._cyclic_cmds:
self._cyclic_cmds[commandcode] = {'cycle': cycle, 'nexttime': 0}
else:
# If another item requested this command already with a longer cycle, use the shorter cycle now
@@ -203,12 +199,12 @@ def parse_item(self, item):
# Process the send config
if self.has_iattr(item.conf, 'comfoair_send'):
commandname = self.get_iattr_value(item.conf, 'comfoair_send')
- if commandname == None:
+ if commandname is None:
return None
elif commandname not in self._commandset:
self.log_err('Item {} contains invalid write command \'{}\'!'.format(item, commandname))
return None
-
+
self.log_info('Item {} writes by using command \'{}\''.format(item, commandname))
return self.update_item
else:
@@ -221,7 +217,7 @@ def update_item(self, item, caller=None, source=None, dest=None):
if caller != 'ComfoAir' and self.has_iattr(item.conf, 'comfoair_send'):
commandname = self.get_iattr_value(item.conf, 'comfoair_send')
- if type(item) != int:
+ if type(item) is not int:
value = int(item())
else:
value = item()
@@ -238,18 +234,18 @@ def update_item(self, item, caller=None, source=None, dest=None):
aw = float(readafterwrite)
time.sleep(aw)
self.send_command(readcommandname)
-
- # If commands should be triggered after this write
+
+ # If commands should be triggered after this write
if self.has_iattr(item.conf, 'comfoair_trigger'):
trigger = self.get_iattr_value(item.conf, 'comfoair_trigger')
- if trigger == None:
+ if trigger is None:
self.log_err('Item {} contains invalid trigger command list \'{}\'!'.format(item, trigger))
else:
- tdelay = 5 # default delay
+ tdelay = 5 # default delay
if self.has_iattr(item.conf, 'comfoair_trigger_afterwrite'):
tdelay = float(self.get_iattr_value(item.conf, 'comfoair_trigger_afterwrite'))
- if type(trigger) != list:
- trigger = [trigger]
+ if type(trigger) is not list:
+ trigger = [trigger]
for triggername in trigger:
triggername = triggername.strip()
if triggername is not None and readafterwrite is not None:
@@ -268,32 +264,32 @@ def handle_cyclic_cmds(self):
self.log_debug('Triggering cyclic read command: {}'.format(commandname))
self.send_command(commandname)
entry['nexttime'] = currenttime + entry['cycle']
-
+
def send_command(self, commandname, value=None):
try:
- #self.log_debug('Got a new send job: Command {} with value {}'.format(commandname, value))
-
+ # self.log_debug('Got a new send job: Command {} with value {}'.format(commandname, value))
+
# Get command config
commandconf = self._commandset[commandname]
commandcode = int(commandconf['Command'])
commandcodebytecount = commandconf['CommandBytes']
commandtype = commandconf['Type']
commandvaluebytes = commandconf['ValueBytes']
- #self.log_debug('Command config: {}'.format(commandconf))
-
+ # self.log_debug('Command config: {}'.format(commandconf))
+
# Transform value for write commands
- #self.log_debug('Got value: {}'.format(value))
+ # self.log_debug('Got value: {}'.format(value))
if 'ValueTransform' in commandconf and value is not None and value != '' and commandtype == 'Write':
commandtransform = commandconf['ValueTransform']
value = self.value_transform(value, commandtype, commandtransform)
- #self.log_debug('Transformed value using method {} to {}'.format(commandtransform, value))
-
+ # self.log_debug('Transformed value using method {} to {}'.format(commandtransform, value))
+
# Build value byte array
valuebytes = bytearray()
if value is not None and commandvaluebytes > 0:
valuebytes = self.int2bytes(value, commandvaluebytes)
- #self.log_debug('Created value bytes: {}'.format(valuebytes))
-
+ # self.log_debug('Created value bytes: {}'.format(valuebytes))
+
# Calculate the checksum
commandbytes = self.int2bytes(commandcode, commandcodebytecount)
payload = bytearray()
@@ -301,7 +297,7 @@ def send_command(self, commandname, value=None):
if len(valuebytes) > 0:
payload.extend(valuebytes)
checksum = self.calc_checksum(payload)
-
+
# Build packet
packet = bytearray()
packet.extend(self.int2bytes(self._controlset['PacketStart'], 2))
@@ -311,22 +307,22 @@ def send_command(self, commandname, value=None):
packet.extend(self.int2bytes(checksum, 1))
packet.extend(self.int2bytes(self._controlset['PacketEnd'], 2))
self.log_debug('Preparing command {} with value {} (transformed to value byte \'{}\') to be sent.'.format(commandname, value, self.bytes2hexstring(valuebytes)))
-
+
# Use a lock to allow only one sender at a time
self._lock.acquire()
if not self.connected:
raise Exception("No connection to ComfoAir.")
-
+
try:
self.send_bytes(packet)
self.log_debug('Successfully sent packet: {}'.format(self.bytes2hexstring(packet)))
except Exception as e:
raise Exception('Exception while sending: {}'.format(e))
-
+
if commandtype == 'Read':
packet = bytearray()
-
+
# Try to receive a packet start, a command and a data length byte
firstpartlen = len(self._packetstart) + self._commandlength + 1
while self.alive and len(packet) < firstpartlen:
@@ -335,9 +331,9 @@ def send_command(self, commandname, value=None):
self.log_debug('Trying to receive {} bytes for the first part of the response.'.format(bytestoreceive))
chunk = self.read_bytes(bytestoreceive)
self.log_debug('Received {} bytes chunk of response part 1: {}'.format(len(chunk), self.bytes2hexstring(chunk)))
- if len(chunk) == 0:
+ if len(chunk) == 0:
raise Exception('Received 0 bytes chunk - ignoring packet!')
-
+
# Cut away old ACK (but only if the telegram wasn't started already)
if len(packet) == 0:
chunk = self.remove_ack_begin(chunk)
@@ -346,11 +342,11 @@ def send_command(self, commandname, value=None):
raise Exception("error receiving first part of packet: timeout")
except Exception as e:
raise Exception("error receiving first part of packet: {}".format(e))
-
+
datalen = packet[firstpartlen - 1]
- #self.log_info('Got a data length of: {}'.format(datalen))
+ # self.log_info('Got a data length of: {}'.format(datalen))
packetlen = firstpartlen + datalen + self._checksumlength + len(self._packetend)
-
+
# Try to receive the second part of the packet
while self.alive and len(packet) < packetlen or packet[-2:] != self._packetend:
try:
@@ -358,42 +354,42 @@ def send_command(self, commandname, value=None):
if len(packet) >= packetlen and packet[-2:] != self._packetend:
packetlen = len(packet) + 1
self.log_debug('Extended packet length because of encoded characters.'.format(self.bytes2hexstring(chunk)))
-
+
# Receive next chunk
bytestoreceive = packetlen - len(packet)
self.log_debug('Trying to receive {} bytes for the second part of the response.'.format(bytestoreceive))
chunk = self.read_bytes(bytestoreceive)
self.log_debug('Received {} bytes chunk of response part 2: {}'.format(len(chunk), self.bytes2hexstring(chunk)))
packet.extend(chunk)
- if len(chunk) == 0:
+ if len(chunk) == 0:
raise Exception('Received 0 bytes chunk - ignoring packet!')
except socket.timeout:
raise Exception("error receiving second part of packet: timeout")
except Exception as e:
raise Exception("error receiving second part of packet: {}".format(e))
-
+
# Send ACK
self.send_bytes(self._acknowledge)
-
+
# Parse response
self.parse_response(packet)
-
+
except Exception as e:
self.disconnect()
self.log_err("send_command failed: {}".format(e))
- finally:
+ finally:
# At the end, release the lock
self._lock.release()
def parse_response(self, response):
- #resph = self.bytes2int(response)
+ # resph = self.bytes2int(response)
self.log_debug('Successfully received response: {}'.format(self.bytes2hexstring(response)))
# A telegram looks like this: start sequence (2 bytes), command (2 bytes), data length (1 byte), data, checksum (1 byte), end sequence (2 bytes, already cut away)
commandcodebytes = response[2:4]
- commandcodebytes[1] -= self._reponsecommandinc # The request command of this response is -1 (for comfoair 350)
- commandcodebytes.append(0) # Add a data length byte of 0 (always true for read commands)
+ commandcodebytes[1] -= self._reponsecommandinc # The request command of this response is -1 (for comfoair 350)
+ commandcodebytes.append(0) # Add a data length byte of 0 (always true for read commands)
commandcode = self.bytes2int(commandcodebytes)
# Remove begin and checksum to get the data
@@ -405,8 +401,8 @@ def parse_response(self, response):
# Validate checksum
packetpart = bytearray()
- packetpart.extend(response[2:5]) # Command and data length
- packetpart.extend(databytes) # Decoded data bytes
+ packetpart.extend(response[2:5]) # Command and data length
+ packetpart.extend(databytes) # Decoded data bytes
checksum = self.calc_checksum(packetpart)
receivedchecksum = response[len(response) - len(self._packetend) - 1]
if (receivedchecksum != checksum):
@@ -437,7 +433,7 @@ def parse_response(self, response):
# Extract value
valuebytes = databytes[index:index + commandvaluebytes]
rawvalue = self.bytes2int(valuebytes)
-
+
# Tranform value
value = self.value_transform(rawvalue, commandtype, commandtransform)
self.log_debug('Matched command {} and read transformed value {} (raw value was {}) from byte position {} and byte length {}.'.format(commandname, value, rawvalue, commandresppos, commandvaluebytes))
@@ -448,20 +444,24 @@ def parse_response(self, response):
self.log_err('Telegram did not contain enough data bytes for the configured command {} to extract a value!'.format(commandname))
def run(self):
+ # automatically (re)connect
+ self._sh.connections.monitor(self)
+
self.alive = True
- self._sh.scheduler.add('ComfoAir-init', self.send_init_commands, prio=5, cycle=600, offset=2)
+ self.scheduler_add('ComfoAir-init', self.send_init_commands, prio=5, cycle=600, offset=2)
maxloops = 20
- loops = 0
+ loops = 0
while self.alive and not self._initread and loops < maxloops: # wait for init read to finish
time.sleep(0.5)
loops += 1
- self._sh.scheduler.remove('ComfoAir-init')
-
+ self.scheduler_remove('ComfoAir-init')
+
def stop(self):
- self._sh.scheduler.remove('ComfoAir-cyclic')
self.alive = False
+ self._sh.connections.remove(self)
+ self.scheduler_remove('ComfoAir-cyclic')
self.disconnect()
-
+
def send_init_commands(self):
try:
# Do the init read commands
@@ -471,19 +471,19 @@ def send_init_commands(self):
for commandcode in self._init_cmds:
commandname = self.commandname_by_commandcode(commandcode)
self.send_command(commandname)
-
+
# Find the shortest cycle
shortestcycle = -1
for commandname in list(self._cyclic_cmds.keys()):
entry = self._cyclic_cmds[commandname]
if shortestcycle == -1 or entry['cycle'] < shortestcycle:
shortestcycle = entry['cycle']
-
+
# Start the worker thread
if shortestcycle != -1:
# Balance unnecessary calls and precision
workercycle = int(shortestcycle / 2)
- self._sh.scheduler.add('ComfoAir-cyclic', self.handle_cyclic_cmds, cycle=workercycle, prio=5, offset=0)
+ self.scheduler_add('ComfoAir-cyclic', self.handle_cyclic_cmds, cycle=workercycle, prio=5, offset=0)
self.log_info('Added cyclic worker thread ({} sec cycle). Shortest item update cycle found: {} sec.'.format(workercycle, shortestcycle))
finally:
self._initread = True
@@ -494,30 +494,30 @@ def remove_ack_begin(self, packet):
while len(packet) >= acklen and packet[0:acklen] == self._acknowledge:
packet = packet[acklen:]
return packet
-
+
def calc_checksum(self, packetpart):
return (sum(packetpart) + 173) % 256
-
- def log_debug(self, text):
+
+ def log_debug(self, text):
self.logger.debug('ComfoAir: {}'.format(text))
- def log_info(self, text):
+ def log_info(self, text):
self.logger.info('ComfoAir: {}'.format(text))
- def log_err(self, text):
+ def log_err(self, text):
self.logger.error('ComfoAir: {}'.format(text))
-
+
def int2bytes(self, value, length):
# Limit value to the passed byte length
value = value % (2 ** (length * 8))
return value.to_bytes(length, byteorder='big')
-
+
def bytes2int(self, bytesvalue):
return int.from_bytes(bytesvalue, byteorder='big', signed=False)
-
+
def bytes2hexstring(self, bytesvalue):
return ":".join("{:02x}".format(c) for c in bytesvalue)
-
+
def encode_specialchars(self, packet):
specialchar = self._controlset['SpecialCharacter']
encodedpacket = bytearray()
@@ -528,9 +528,9 @@ def encode_specialchars(self, packet):
# Encoding works by doubling the special char
self.log_debug('Encoded special char at position {} of data bytes {}.'.format(count, self.bytes2hexstring(packet)))
encodedpacket.append(char)
- #self.log_debug('Encoded data bytes: {}.'.format(encodedpacket))
+ # self.log_debug('Encoded data bytes: {}.'.format(encodedpacket))
return encodedpacket
-
+
def decode_specialchars(self, packet):
specialchar = self._controlset['SpecialCharacter']
decodedpacket = bytearray()
@@ -549,7 +549,7 @@ def decode_specialchars(self, packet):
# Reset dropping marker
specialcharremoved = 0
return decodedpacket
-
+
def value_transform(self, value, commandtype, transformmethod):
if transformmethod == 'Temperature':
if commandtype == 'Read':
@@ -562,7 +562,7 @@ def value_transform(self, value, commandtype, transformmethod):
elif commandtype == 'Write':
return int(1875000 / value)
return value
-
+
def commandname_by_commandcode(self, commandcode):
for commandname in self._commandset.keys():
if self._commandset[commandname]['Command'] == commandcode:
diff --git a/comfoair/plugin.yaml b/comfoair/plugin.yaml
index 806000e79..7438bad8e 100755
--- a/comfoair/plugin.yaml
+++ b/comfoair/plugin.yaml
@@ -12,11 +12,11 @@ plugin:
documentation: https://github.com/smarthomeNG/smarthome/wiki/Comfoair-Plugin # url of documentation (wiki) page
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/31291-neues-plugin-comfoair-kwl-wohnraumlüftung-zehnder-paul-wernig
- version: 1.3.0 # Plugin version
+ version: 1.3.1 # Plugin version
sh_minversion: 1.3 # 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: ComfoAir # class containing the plugin
parameters:
@@ -30,16 +30,19 @@ parameters:
valid_list:
- comfoair350
- comfoair500
+
host:
type: ip
description:
de: 'Netzwerverbindung: Hostname/IP des KWL Systems'
en: 'Network connection: Hostname/IP of KWL system'
+
port:
type: int
description:
de: 'Netzwerkverbindung: Port des KWL Systems'
en: 'Network connection: Port of KWL system'
+
serialport:
type: str
description:
@@ -61,22 +64,22 @@ item_attributes:
comfoair_read_afterwrite:
type: num
description:
- de: 'Konfiguriert eine Verzögerung in Sekunden nachdem ein Lesekommando nach einem Schreibkommando an das KWL System geschickt wird.'
+ de: 'Konfiguriert eine Verzögerung in Sekunden, nachdem ein Lesekommando nach einem Schreibkommando an das KWL System geschickt wird.'
en: 'Configures delay in seconds to issue a read command after write command.'
comfoair_read_cycle:
type: num
description:
- de: 'Konfiguriert ein Interval in Sekunden für das Lesekommando.'
+ de: 'Konfiguriert ein Intervall in Sekunden für das Lesekommando.'
en: 'Configures a interval in seconds for the read command.'
comfoair_init:
type: bool
description:
- de: 'Konfiguriert ob der Wert aus dem KWL System initialisiert werden soll.'
+ de: 'Konfiguriert, ob der Wert aus dem KWL System initialisiert werden soll.'
en: 'Configures to initialize the item value with the value from the KWL system.'
comfoair_trigger:
type: list(str)
description:
- de: 'Konfiguriert Lesekommandos die nach einem Schreibvorgang auf das Item aufgerufen werden.'
+ de: 'Konfiguriert Lesekommandos, die nach einem Schreibvorgang auf das Item aufgerufen werden.'
en: 'Configures read commands after an update to the item.'
comfoair_trigger_afterwrite:
type: num
diff --git a/helios/__init__.py b/helios/__init__.py
index ff7e14bd7..f8c97d53d 100755
--- a/helios/__init__.py
+++ b/helios/__init__.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+# !/usr/bin/env python
#########################################################################
# Copyright 2014 Marcel Tiews marcel.tiews@gmail.com
# Modified 2014-2017 by René Jahncke aka Tom-Bom-badil @ github.com
@@ -22,11 +22,8 @@
import sys
import serial
import logging
-import socket
import threading
-import struct
import time
-import datetime
import array
from lib.model.smartplugin import SmartPlugin
@@ -34,10 +31,10 @@
# old / removed: logger = logging.getLogger("")
# Old CONST's - previous definitions
-#CONST_BUSMEMBER__MAINBOARD = 0x11
-#CONST_BUSMEMBER__SLAVEBOARDS = 0x10
-#CONST_BUSMEMBER__CONTROLBOARDS = 0x20
-#CONST_BUSMEMBER__ME = 0x2F
+# CONST_BUSMEMBER__MAINBOARD = 0x11
+# CONST_BUSMEMBER__SLAVEBOARDS = 0x10
+# CONST_BUSMEMBER__CONTROLBOARDS = 0x20
+# CONST_BUSMEMBER__ME = 0x2F
# Broadcast addresses - no way to address slave boards in the units directly (according to Vallox)
@@ -45,10 +42,10 @@
CONST_BUS_ALL_REMOTES = 0x20
# Individual addresses
-CONST_BUS_MAINBOARD1 = 0x11 # 1st of max 15 ventilation units (mainboards 1-F)
-CONST_BUS_REMOTE1 = 0x21 # 1st of max 15 remote controls (remotes 1-F, default jumper = 1)
-CONST_BUS_LON = 0x28 # default for LON bus module (just for information --> expensive)
-CONST_BUS_ME = 0x2F # stealth mode - we are behaving like a regular remote control
+CONST_BUS_MAINBOARD1 = 0x11 # 1st of max 15 ventilation units (mainboards 1-F)
+CONST_BUS_REMOTE1 = 0x21 # 1st of max 15 remote controls (remotes 1-F, default jumper = 1)
+CONST_BUS_LON = 0x28 # default for LON bus module (just for information --> expensive)
+CONST_BUS_ME = 0x2F # stealth mode - we are behaving like a regular remote control
CONST_MAP_VARIABLES_TO_ID = {
"power_state" : {"varid" : 0xA3, 'type': 'bit', 'bitposition': 0, 'read': True, 'write': True },
@@ -70,9 +67,9 @@
"boost_status" : {"varid" : 0x71, 'type': 'bit', 'bitposition': 6, 'read': True, 'write': False },
"boost_remaining" : {"varid" : 0x79, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': False },
"fan_in_on_off" : {"varid" : 0x08, 'type': 'bit', 'bitposition': 3, 'read': True, 'write': True },
- "fan_in_percent" : {"varid" : 0xB0, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
+ "fan_in_percent" : {"varid" : 0xB0, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
"fan_out_on_off" : {"varid" : 0x08, 'type': 'bit', 'bitposition': 5, 'read': True, 'write': True },
- "fan_out_percent" : {"varid" : 0xB1, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
+ "fan_out_percent" : {"varid" : 0xB1, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
"clean_filter" : {"varid" : 0xAB, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': True },
"device_error" : {"varid" : 0x36, 'type': 'dec', 'bitposition': -1, 'read': True, 'write': False }
}
@@ -96,54 +93,56 @@ class HeliosException(Exception):
class HeliosBase(SmartPlugin):
- PLUGIN_VERSION = "1.4.2"
+ PLUGIN_VERSION = "1.4.3"
ALLOW_MULTIINSTANCE = False
- def __init__(self, tty='/dev/ttyUSB0'):
+ def __init__(self, **kwargs):
self.logger = logging.getLogger(__name__)
- self._tty = tty
self._is_connected = False
- self._port = False
self._lock = threading.Lock()
-
+ if 'tty' in kwargs:
+ self._tty = kwargs['tty']
+ if 'port' in kwargs:
+ self._port = kwargs['port']
+
def connect(self):
if self._is_connected and self._port:
return True
-
+
try:
self.logger.debug("Helios: Connecting...")
self._port = serial.Serial(
- self._tty,
- baudrate=9600,
- bytesize=serial.EIGHTBITS,
- parity=serial.PARITY_NONE,
- stopbits=serial.STOPBITS_ONE,
+ self._tty,
+ baudrate=9600,
+ bytesize=serial.EIGHTBITS,
+ parity=serial.PARITY_NONE,
+ stopbits=serial.STOPBITS_ONE,
timeout=1)
self._is_connected = True
return True
except:
self.logger.error("Helios: Could not open {0}.".format(self._tty))
return False
-
+
def disconnect(self):
if self._is_connected and self._port:
self.logger.debug("HeliosBase: Disconnecting...")
self._port.close()
self._is_connected = False
-
+
def _createTelegram(self, sender, receiver, function, value):
- telegram = [1,sender,receiver,function,value,0]
+ telegram = [1, sender, receiver, function, value, 0]
telegram[5] = self._calculateCRC(telegram)
return telegram
-
+
def _waitForSilence(self):
# Modbus RTU only allows one master (client which controls communication).
# So lets try to wait a bit and jump in when nobody's speaking.
# Modbus defines a waittime of 3,5 Characters between telegrams:
- # (1/9600baud * (1 Start bit + 8 Data bits + 1 Parity bit + 1 Stop bit)
+ # (1/9600baud * (1 Start bit + 8 Data bits + 1 Parity bit + 1 Stop bit)
# => about 4ms
# Lets go with 7ms! ;O)
-
+
gotSlot = False
backupTimeout = self._port.timeout
end = time.time() + 3
@@ -155,128 +154,127 @@ def _waitForSilence(self):
gotSlot = True
break
self._port.timeout = backupTimeout
- return gotSlot
+ return gotSlot
def _sendTelegram(self, telegram):
if not self._is_connected:
return False
-
+
self.logger.debug("Helios: Sending telegram '{0}'".format(self._telegramToString(telegram)))
self._port.write(bytearray(telegram))
return True
-
+
def _readTelegram(self, sender, receiver, datapoint):
# sometimes a lot of garbage is received...so lets get a bit robust
# and read a bit of this junk and see whether we are getting something
# useful out of it!
# How long does it take until something useful is received???
timeout = time.time() + 1
- telegram = [0,0,0,0,0,0]
+ telegram = [0, 0, 0, 0, 0, 0]
while self._is_connected and timeout > time.time():
char = self._port.read(1)
- if(len(char) > 0):
+ if (len(char) > 0):
byte = bytearray(char)[0]
telegram.pop(0)
telegram.append(byte)
# Telegrams always start with a 0x01, is the CRC valid?, ...
- if (telegram[0] == 0x01 and
- telegram[1] == sender and
- telegram[2] == receiver and
- telegram[3] == datapoint and
- telegram[5] == self._calculateCRC(telegram)):
+ if (telegram[0] == 0x01 and
+ telegram[1] == sender and
+ telegram[2] == receiver and
+ telegram[3] == datapoint and
+ telegram[5] == self._calculateCRC(telegram)):
self.logger.debug("Telegram received '{0}'".format(self._telegramToString(telegram)))
return telegram[4]
- return None
-
+
def _calculateCRC(self, telegram):
sum = 0
for c in telegram[:-1]:
sum = sum + c
return sum % 256
-
+
def _telegramToString(self, telegram):
str = ""
for c in telegram:
# str = str + hex(c) + " " 0x01 was showing as 0x1, 0x1A was showing as 0x1a
- str = str + '0x%0*X' % (2,c) + " "
- str = str[:-1] # remove trailing space
+ str = str + '0x%0*X' % (2, c) + " "
+ str = str[:-1] # remove trailing space
return str
-
+
def _convertFromRawValue(self, varname, rawvalue):
value = None
vardef = CONST_MAP_VARIABLES_TO_ID[varname]
-
+
if vardef["type"] == "temperature":
value = CONST_TEMPERATURE[rawvalue]
elif vardef["type"] == "fanspeed":
if rawvalue == 0x01:
value = 1
- elif rawvalue == 0x03:
+ elif rawvalue == 0x03:
value = 2
- elif rawvalue == 0x07:
+ elif rawvalue == 0x07:
value = 3
- elif rawvalue == 0x0F:
+ elif rawvalue == 0x0F:
value = 4
- elif rawvalue == 0x1F:
+ elif rawvalue == 0x1F:
value = 5
- elif rawvalue == 0x3F:
+ elif rawvalue == 0x3F:
value = 6
- elif rawvalue == 0x7F:
+ elif rawvalue == 0x7F:
value = 7
- elif rawvalue == 0xFF:
+ elif rawvalue == 0xFF:
value = 8
else:
value = None
elif vardef["type"] == "bit":
value = rawvalue >> vardef["bitposition"] & 0x01
- elif vardef["type"] == "dec": # decimal value
+ elif vardef["type"] == "dec": # decimal value
value = rawvalue
-
- return value
+
+ return value
def _convertFromValue(self, varname, value, prevvalue):
rawvalue = None
vardef = CONST_MAP_VARIABLES_TO_ID[varname]
-
+
if vardef['type'] == "temperature":
rawvalue = CONST_TEMPERATURE.index(int(value))
elif vardef["type"] == "fanspeed":
value = int(value)
if value == 1:
rawvalue = 0x01
- elif value == 2:
+ elif value == 2:
rawvalue = 0x03
- elif value == 3:
+ elif value == 3:
rawvalue = 0x07
- elif value == 4:
+ elif value == 4:
rawvalue = 0x0F
- elif value == 5:
+ elif value == 5:
rawvalue = 0x1F
- elif value == 6:
+ elif value == 6:
rawvalue = 0x3F
- elif value == 7:
+ elif value == 7:
rawvalue = 0x7F
- elif value == 8:
+ elif value == 8:
rawvalue = 0xFF
else:
rawvalue = None
elif vardef["type"] == "bit":
# for bits we have to keep the other bits of the byte (previous value)
- if value in (True,1,"true","True","1","On","on"):
+ if value in (True, 1, "true", "True", "1", "On", "on"):
rawvalue = prevvalue | (1 << vardef["bitposition"])
else:
rawvalue = prevvalue & ~(1 << vardef["bitposition"])
- elif vardef["type"] == "dec": # decimal value
+ elif vardef["type"] == "dec": # decimal value
rawvalue = int(value)
-
- return rawvalue
-
- def writeValue(self,varname, value):
- if CONST_MAP_VARIABLES_TO_ID[varname]["write"] != True:
+
+ return rawvalue
+
+ def writeValue(self, varname, value):
+ if CONST_MAP_VARIABLES_TO_ID[varname]["write"] is not True:
self.logger.error("Helios: Variable {0} may not be written!".format(varname))
- return False
+ return False
success = False
-
+
self._lock.acquire()
try:
# if we have got to write a single bit, we need the current (byte) value to
@@ -287,43 +285,42 @@ def writeValue(self,varname, value):
# Send poll request
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_MAINBOARD1,
- 0,
+ CONST_BUS_MAINBOARD1,
+ 0,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
self._sendTelegram(telegram)
# Read response
currentval = self._readTelegram(
- CONST_BUS_MAINBOARD1,
- CONST_BUS_ME,
+ CONST_BUS_MAINBOARD1,
+ CONST_BUS_ME,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
- if currentval == None:
- self.logger.error("Helios: Sending value to ventilation system failed. Can not read current variable value '{0}'."
- .format(varname))
+ if currentval is None:
+ self.logger.error("Helios: Sending value to ventilation system failed. Can not read current variable value '{0}'.".format(varname))
return False
rawvalue = self._convertFromValue(varname, value, currentval)
- else:
+ else:
rawvalue = self._convertFromValue(varname, value, None)
-
- # send the new value
+
+ # send the new value
if self._waitForSilence():
- if rawvalue != None:
+ if rawvalue is not None:
# Broadcasting value to all remote control boards
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_ALL_REMOTES,
- CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
+ CONST_BUS_ALL_REMOTES,
+ CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
-
+
# Broadcasting value to all mainboards
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_ALL_MAINBOARDS,
- CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
+ CONST_BUS_ALL_MAINBOARDS,
+ CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
rawvalue
)
self._sendTelegram(telegram)
@@ -331,75 +328,75 @@ def writeValue(self,varname, value):
# Writing value to 1st mainboard
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_MAINBOARD1,
- CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
- rawvalue
+ CONST_BUS_MAINBOARD1,
+ CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
+ rawvalue
)
self._sendTelegram(telegram)
-
+
# Send checksum a second time
self._sendTelegram([telegram[5]])
-#################### Special treatment to switch on remote controls after off state:
+ # Special treatment to switch on remote controls after off state:
+ # TODO: doesn't work so far
if CONST_MAP_VARIABLES_TO_ID[varname]["varid"] == 0xA3 and CONST_MAP_VARIABLES_TO_ID[varname]["bitposition"] == 0:
- self.logger.debug("On/off command - special treatment for the remote controls")
+ self.logger.debug("On/off command - special treatment for the remote controls")
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_ALL_REMOTES,
- CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
- rawvalue
+ CONST_BUS_ALL_REMOTES,
+ CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
+ rawvalue
)
self._sendTelegram(telegram)
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_REMOTE1,
- CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
- rawvalue
+ CONST_BUS_REMOTE1,
+ CONST_MAP_VARIABLES_TO_ID[varname]["varid"],
+ rawvalue
)
self._sendTelegram(telegram)
self._sendTelegram([telegram[5]])
-#################### Doesn't work so far
+ # Doesn't work so far
success = True
-
+
else:
- self.logger.error("Helios: Sending value to ventilation system failed. Can not convert value '{0}' for variable '{1}'."
- .format(value,varname))
+ self.logger.error("Helios: Sending value to ventilation system failed. Can not convert value '{0}' for variable '{1}'.".format(value,varname))
success = False
else:
self.logger.error("Helios: Sending value to ventilation system failed. No free slot for sending telegrams available.")
success = False
except Exception as e:
- self.logger.error("Helios: Exception in writeValue() occurred: {0}".format(e))
+ self.logger.error("Helios: Exception in writeValue() occurred: {0}".format(e))
finally:
self._lock.release()
-
+
return success
-
- def readValue(self,varname):
- if CONST_MAP_VARIABLES_TO_ID[varname]["read"] != True:
+
+ def readValue(self, varname):
+ if CONST_MAP_VARIABLES_TO_ID[varname]["read"] is not True:
self.logger.error("Variable {0} may not be read!".format(varname))
return False
value = None
-
+
self._lock.acquire()
try:
- self.logger.debug("Helios: Reading value: {0}".format(varname))
+ self.logger.debug("Helios: Reading value: {0}".format(varname))
if self._waitForSilence():
# Send poll request
telegram = self._createTelegram(
CONST_BUS_ME,
- CONST_BUS_MAINBOARD1,
- 0,
+ CONST_BUS_MAINBOARD1,
+ 0,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
self._sendTelegram(telegram)
# Read response
value = self._readTelegram(
- CONST_BUS_MAINBOARD1,
- CONST_BUS_ME,
+ CONST_BUS_MAINBOARD1,
+ CONST_BUS_ME,
CONST_MAP_VARIABLES_TO_ID[varname]["varid"]
)
if value is not None:
@@ -408,36 +405,37 @@ def readValue(self,varname):
self.logger.debug("Value for {0} ({1}) received: {2}|{3}|{4} --> converted = {5}"
.format(varname, '0x%0*X' % (2, CONST_MAP_VARIABLES_TO_ID[varname]["varid"]),
'0x%0*X' % (2,raw_value), "{0:08b}".format(raw_value), raw_value, value)
- )
+ )
else: # logging as info only, so we stop spamming log file as some noise on the bus seems to be normal
- self.logger.info("Helios: No valid value for '{0}' from ventilation system received."
- .format(varname)
- )
+ self.logger.info("Helios: No valid value for '{0}' from ventilation system received.".format(varname)
+ )
else:
self.logger.warning("Helios: Reading value from ventilation system failed. No free slot to send poll request available.")
except Exception as e:
- self.logger.error("Helios: Exception in readValue() occurred: {0}".format(e))
+ self.logger.error("Helios: Exception in readValue() occurred: {0}".format(e))
finally:
self._lock.release()
-
+
return value
-
-class Helios(HeliosBase):
+
+class Helios(HeliosBase):
_items = {}
-
- def __init__(self, smarthome, tty, cycle=300):
- HeliosBase.__init__(self, tty)
- self._sh = smarthome
- self._cycle = int(cycle)
+
+ def __init__(self):
+ self._tty = self.get_parameter_value('tty')
+ self._cycle = self.get_parameter_value('cycle')
+ self._port = None
+ super().__init__()
self._alive = False
-
+
def run(self):
self.connect()
self._alive = True
self._sh.scheduler.add('Helios', self._update, cycle=self._cycle)
def stop(self):
+ self._sh.scheduler.remove('Helios')
self.disconnect()
self._alive = False
@@ -449,62 +447,65 @@ def parse_item(self, item):
return self.update_item
else:
self.logger.warning("Helios: Ignoring unknown variable '{0}'".format(varname))
-
+
def update_item(self, item, caller=None, source=None, dest=None):
if caller != 'Helios':
- self.writeValue(item.conf['helios_var'], item())
-
+ self.writeValue(item.conf['helios_var'], item())
+
def _update(self):
self.logger.debug("Helios: Updating values")
for var in self._items.keys():
val = self.readValue(var)
- if val != None:
- self._items[var](val,"Helios")
+ if val is not None:
+ self._items[var](val, "Helios")
+
-
def main():
- import argparse
-
+ import argparse
+
parser = argparse.ArgumentParser(
- description="Helios ventilation system commandline interface.",
- epilog="Without arguments all readable values using default tty will be retrieved.",
- argument_default=argparse.SUPPRESS)
- parser.add_argument("-t", "--tty", dest="port", default="/dev/ttyUSB0", help="Serial device to use")
+ description="Helios ventilation system commandline interface.",
+ epilog="Without arguments all readable values using default tty will be retrieved.",
+ argument_default=argparse.SUPPRESS
+ )
+ parser.add_argument("-t", "--tty", dest="tty", default="/dev/ttyUSB0", help="Serial device to use")
parser.add_argument("-r", "--read", dest="read_var", help="Read variables from ventilation system")
parser.add_argument("-w", "--write", dest="write_var", help="Write variable to ventilation system")
parser.add_argument("-v", "--value", dest="value", help="Value to write (required with option -v)")
parser.add_argument("-d", "--debug", dest="enable_debug", action="store_true", help="Prints debug statements.")
args = vars(parser.parse_args())
-
+
if "write_var" in args.keys() and "value" not in args.keys():
parser.print_usage()
return
+ logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# old log version
-# ch = logging.StreamHandler()
-# if "enable_debug" in args.keys():
-# ch.setLevel(logging.DEBUG)
-# else:
-# ch.setLevel(logging.INFO)
-# formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
-# ch.setFormatter(formatter)
-# logger.addHandler(ch)
+# ch = logging.StreamHandler()
+# if "enable_debug" in args.keys():
+# ch.setLevel(logging.DEBUG)
+# else:
+# ch.setLevel(logging.INFO)
+# formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
+# ch.setFormatter(formatter)
+# logger.addHandler(ch)
+ helios = None
try:
- helios = HeliosBase(args["port"])
+ helios = HeliosBase(tty=args["tty"])
helios.connect()
if not helios._is_connected:
raise Exception("Not connected")
-
+
if "read_var" in args.keys():
- print("{0} = {1}".format(args["read_var"],helios.readValue(args["read_var"])))
+ print("{0} = {1}".format(args["read_var"], helios.readValue(args["read_var"])))
elif "write_var" in args.keys():
helios.writeValue(args["write_var"],args["value"])
else:
for var in CONST_MAP_VARIABLES_TO_ID.keys():
- print("{0} = {1}".format(var,helios.readValue(var)))
+ print("{0} = {1}".format(var, helios.readValue(var)))
except Exception as e:
print("Exception: {0}".format(e))
return 1
@@ -512,5 +513,6 @@ def main():
if helios:
helios.disconnect()
+
if __name__ == "__main__":
- sys.exit(main())
+ sys.exit(main())
diff --git a/helios/plugin.yaml b/helios/plugin.yaml
index 457c49c97..2a643b9ed 100755
--- a/helios/plugin.yaml
+++ b/helios/plugin.yaml
@@ -1,3 +1,6 @@
+%YAML 1.1
+---
+
plugin:
type: interface
description:
@@ -9,10 +12,10 @@ plugin:
keywords: 'helios vallox ventilation'
documentation: https://github.com/Tom-Bom-badil/helios/wiki
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/40092-erweiterung-helios-vallox-plugin
- version: 1.4.2
- sh_minversion: 1.1
- multi_instance: False
- restartable: unknown
+ version: 1.4.3
+ sh_minversion: 1.6
+ multi_instance: false
+ restartable: true
classname: 'Helios'
parameters:
diff --git a/intercom_2n/__init__.py b/intercom_2n/__init__.py
index 37fba4268..a859fe667 100755
--- a/intercom_2n/__init__.py
+++ b/intercom_2n/__init__.py
@@ -31,17 +31,22 @@
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+
class Intercom2n(SmartPlugin):
- PLUGIN_VERSION = "1.3.0.1"
+ PLUGIN_VERSION = "1.3.1"
ALLOW_MULTIINSTANCE = False
- def __init__(self, sh, intercom_ip, ssl=False, auth_type=0, username=None, password=None):
- self._sh = sh
+ def __init__(self):
+ self._intercom_ip = self.get_parameter_value('intercom_ip')
+ self._ssl = self.get_parameter_value('ssl')
+ self._auth_type = self.get_parameter_value('auth_type')
+ self._username = self.get_parameter_value('username')
+ self._password = self.get_parameter_value('password')
self.is_stopped = False
self.sid = None
self._logger = logging.getLogger(__name__)
self.event_timeout = 30
- self.ip_cam = IPCam(intercom_ip, ssl=ssl, auth_type=auth_type, user=username, password=password)
+ self.ip_cam = IPCam(self._intercom_ip, ssl=self._ssl, auth_type=self._auth_type, user=self._username, password=self._password)
# item dictionaries for events
self.possible_events = [
@@ -104,7 +109,7 @@ def get_events(self):
def parse_event_data(self, raw_data):
try:
- raw_data =json.loads(raw_data)
+ raw_data = json.loads(raw_data)
except Exception:
self._logger.warning("Unknown 2n_event: '{event}' not in dictionary format.".format(event=raw_data))
return
@@ -231,8 +236,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'firmware_upload':
# check for child item firmware_filepath
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "firmware_file":
if os.path.exists(child_item()):
parent_item(self.ip_cam.commands.firmware_upload(child_item()))
@@ -241,16 +246,16 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'config_get':
# check for child item config_file
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "config_file":
parent_item(self.ip_cam.commands.config_get(filename=child_item()))
break
elif command == 'config_upload':
# check for child item firmware_filepath
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "config_file":
if os.path.exists(child_item()):
parent_item(self.ip_cam.commands.config_upload(child_item()))
@@ -261,8 +266,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'switch_status':
switch = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "switch":
switch = child_item()
break
@@ -272,8 +277,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
action = None
response = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "switch":
switch = child_item()
elif path == "action":
@@ -286,8 +291,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'io_caps':
port = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "port":
port = child_item()
break
@@ -295,8 +300,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'io_status':
port = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "port":
port = child_item()
break
@@ -306,8 +311,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
action = None
response = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "port":
port = child_item()
elif path == "action":
@@ -320,50 +325,50 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'phone_status':
account = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "account":
account = child_item()
break
parent_item(self.ip_cam.commands.phone_status(account))
elif command == 'call_status':
- session = None
- child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
- if path == "session":
- session = child_item()
- break
- parent_item(self.ip_cam.commands.call_status(session))
+ session = None
+ child_items = parent_item.return_children()
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
+ if path == "session":
+ session = child_item()
+ break
+ parent_item(self.ip_cam.commands.call_status(session))
elif command == 'call_dial':
- number = None
- child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
- if path == "number":
- number = child_item()
- break
- parent_item(self.ip_cam.commands.call_dial(number))
+ number = None
+ child_items = parent_item.return_children()
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
+ if path == "number":
+ number = child_item()
+ break
+ parent_item(self.ip_cam.commands.call_dial(number))
elif command == 'call_answer':
- session = None
- child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
- if path == "session":
- session = child_item()
- break
- parent_item(self.ip_cam.commands.call_answer(session))
+ session = None
+ child_items = parent_item.return_children()
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
+ if path == "session":
+ session = child_item()
+ break
+ parent_item(self.ip_cam.commands.call_answer(session))
elif command == 'call_hangup':
- session = None
- reason = None
- child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
- if path == "session":
- session = child_item()
- if path == "reason":
- reason = child_item()
- parent_item(self.ip_cam.commands.call_hangup(session, reason))
+ session = None
+ reason = None
+ child_items = parent_item.return_children()
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
+ if path == "session":
+ session = child_item()
+ if path == "reason":
+ reason = child_item()
+ parent_item(self.ip_cam.commands.call_hangup(session, reason))
elif command == 'camera_caps':
parent_item(self.ip_cam.commands.camera_caps())
elif command == 'camera_snapshot':
@@ -373,8 +378,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
source = None
time = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "snapshot_file":
snapshot_file = child_item()
if path == "width":
@@ -384,7 +389,7 @@ def update_item(self, item, caller=None, source=None, dest=None):
if path == "source":
source = child_item()
if path == "time":
- time == child_item()
+ time = child_item()
parent_item(self.ip_cam.commands.camera_snapshot(width, height, snapshot_file, source, time))
elif command == 'display_caps':
parent_item(self.ip_cam.commands.display_caps())
@@ -392,22 +397,22 @@ def update_item(self, item, caller=None, source=None, dest=None):
gif_file = None
display = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "gif_file":
gif_file = child_item()
if path == "display":
display = child_item()
parent_item(self.ip_cam.commands.display_upload_image(display, gif_file))
elif command == 'display_delete_image':
- display = None
- child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
- if path == "display":
- display = child_item()
- break
- parent_item(self.ip_cam.commands.display_delete_image(display))
+ display = None
+ child_items = parent_item.return_children()
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
+ if path == "display":
+ display = child_item()
+ break
+ parent_item(self.ip_cam.commands.display_delete_image(display))
elif command == 'log_caps':
parent_item(self.ip_cam.commands.log_caps())
elif command == 'audio_test':
@@ -421,8 +426,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
picture_count = None
timespan = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "to":
to = child_item()
if path == "width":
@@ -441,8 +446,8 @@ def update_item(self, item, caller=None, source=None, dest=None):
elif command == 'pcap':
pcap_file = None
child_items = parent_item.return_children()
- for child_item in child_items:
- path = child_item._name.replace(parent_item._name,'').lstrip('.')
+ for child_item in child_items:
+ path = child_item._name.replace(parent_item._name, '').lstrip('.')
if path == "pcap_file":
pcap_file = child_item()
break
diff --git a/intercom_2n/plugin.yaml b/intercom_2n/plugin.yaml
index 469911e88..996c54c90 100755
--- a/intercom_2n/plugin.yaml
+++ b/intercom_2n/plugin.yaml
@@ -12,27 +12,28 @@ plugin:
# documentation: https://github.com/smarthomeNG/smarthome/wiki/CLI-Plugin # url of documentation (wiki) page
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1030539-plugin-2n-intercom
- version: 1.3.0.1 # Plugin version
- sh_minversion: 1.3 # minimum shNG version to use this plugin
+ version: 1.3.1 # 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 # plugin supports multi instance
- restartable: unknown
+ multi_instance: false # plugin supports multi instance
+ restartable: false
classname: Intercom2n # class containing the plugin
parameters:
# Definition of parameters to be configured in etc/plugin.yaml
-# def __init__(self, sh, intercom_ip, ssl=False, auth_type=0, username=None, password=None):
intercom_ip:
type: ip
description:
de: "Intercom IP Adresse"
en: "IP address of Intercom"
+
ssl:
type: bool
default: False
description:
de: "ssl Verschlüsselung verwenden"
en: "Use ssl encryption"
+
auth_type:
type: int
default: 0
@@ -41,12 +42,14 @@ parameters:
description:
de: "Zu verwendender auth_type (0: no authentication, 1: Basic Authentication, 2: Digest Authentication)"
en: "auth_type to use (0: no authentication, 1: Basic Authentication, 2: Digest Authentication)"
+
username:
type: str
default: None*
description:
de: "Benutzername, falls auth_type > 0"
en: "Usernam, falls auth_type > 0"
+
password:
type: str
default: None*
diff --git a/jvcproj/__init__.py b/jvcproj/__init__.py
index f7f3d5268..c907cc622 100755
--- a/jvcproj/__init__.py
+++ b/jvcproj/__init__.py
@@ -97,10 +97,9 @@ class JVC_DILA_Control(SmartPlugin):
the update functions for the items
"""
ALLOW_MULTIINSTANCE = False
- PLUGIN_VERSION='1.0.1'
+ PLUGIN_VERSION = '1.0.2'
-
- def __init__(self, smarthome, host='0.0.0.0', gammaconf_dir='/usr/local/smarthome/etc/jvcproj/'):
+ def __init__(self):
"""
Initalizes the plugin. The parameters describe for this method are pulled from the entry in plugin.conf.
:param host: JVC DILA Projectors IP address
@@ -108,10 +107,9 @@ def __init__(self, smarthome, host='0.0.0.0', gammaconf_dir='/usr/local/smarthom
:port is fixed to 20554
"""
super().__init__()
- self.logger = logging.getLogger(__name__)
- self._sh=smarthome
- self.host_port = (host, 20554)
- self.gammaconf_dir = gammaconf_dir
+ self.host = self.get_parameter_value('host')
+ self.gammaconf_dir = self.get_parameter_value('gammaconf_dir')
+ self.host_port = (self.host, 20554)
self.logger.debug("Plugin '{}': configured for host: '{}'".format(self.get_fullname(), self.host_port))
def run(self):
@@ -164,7 +162,7 @@ def update_item(self, item, caller=None, source=None, dest=None):
:param source: if given it represents the source
:param dest: if given it represents the dest
"""
- if item():
+ if item() and self.alive:
if self.has_iattr(item.conf, 'jvcproj_cmd'):
if self.get_iattr_value(item.conf, 'jvcproj_cmd') == 'None':
self.logger.debug("Plugin '{}': no command given for update_item '{}'. Please check jvcproj_cmd!"
@@ -184,17 +182,16 @@ def update_item(self, item, caller=None, source=None, dest=None):
.format(self.get_fullname(), item, caller, source, dest))
self.check_gamma_cmd(item)
-
def check_gamma_cmd(self, item):
"""check gamma options to import new gammatable"""
self.logger.debug("Plugin '{}': checking for gamma.conf an correct gamma input (must a custom gammatable) in '{}' : '{}'."
.format(self.get_fullname(), item, self.get_iattr_value(item.conf, 'jvcproj_gamma')))
- _checklist = (self.get_iattr_value(item.conf, 'jvcproj_gamma').replace(' ','')).split('|')
+ _checklist = (self.get_iattr_value(item.conf, 'jvcproj_gamma').replace(' ', '')).split('|')
if len(_checklist) != 2:
self.logger.debug("Plugin '{}': ERROR! Item:'{}': exactly two arguments (file and custom gamma table) must be given!"
.format(self.get_fullname(), item))
return
- _cmdlist=[]
+ _cmdlist = []
if self.gammaconf_dir[-1] != '/':
self.gammaconf_dir = self.gammaconf_dir + '/'
if os_path.isfile(self.gammaconf_dir + _checklist[0]) is False:
@@ -243,7 +240,7 @@ def load_table(self, data):
def check_gammadata(self, table):
"""Check gamma data from file"""
gammadata = table
- if gammadata is None :
+ if gammadata is None:
return None
if len(gammadata) == 256:
gammadata = [gammadata, gammadata, gammadata]
@@ -268,12 +265,11 @@ def le16_split(self, colortable):
yield val % 256
yield int(val / 256)
-
def check_cmd(self, item):
"""create command list and execute low level string validation for each command"""
self.logger.debug("Plugin '{}': create commandlist for item '{}' : '{}' and check command(s)."
.format(self.get_fullname(), item, self.get_iattr_value(item.conf, 'jvcproj_cmd')))
- _checklist = (self.get_iattr_value(item.conf, 'jvcproj_cmd').replace(' ','')).split('|')
+ _checklist = (self.get_iattr_value(item.conf, 'jvcproj_cmd').replace(' ', '')).split('|')
_cmdlist = []
for _cmd in _checklist:
if _cmd.upper()[2:6] == UNIT_ID and _cmd.upper()[-2:] == END:
@@ -297,7 +293,7 @@ def handleconn_op(self, cmdlist):
"""handle connection and sending commands for jvcproj_cmd"""
self.connect()
for cmd in cmdlist:
- if cmd[:2] == REQ: ##maybe in the future??
+ if cmd[:2] == REQ: # maybe in the future??
self.logger.debug("Plugin '{}': WARNING! A request is not yet supported!"
.format(self.get_fullname()))
elif cmd[:2] == OPE:
@@ -308,7 +304,6 @@ def handleconn_op(self, cmdlist):
.format(self.get_fullname(), cmd))
self.disconnect('finished! Now disconnecting!')
-
def connect(self):
"""Open network connection to projector and perform handshake"""
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -330,13 +325,13 @@ def set(self, cmd):
self.send(binascii.a2b_hex(cmd))
self.expect(binascii.a2b_hex(ACK + cmd[2:10] + END))
except Timeout:
- self.disconnect('ERROR! Command not acknowledged! Aborting!')
- raise CommandNack('Command not acknowledged', cmd)
+ self.disconnect('ERROR! Command not acknowledged! Aborting!')
+ raise CommandNack('Command not acknowledged', cmd)
def get(self):
pass
- def disconnect(self, message ='disconnecting...'):
+ def disconnect(self, message='disconnecting...'):
"""Close socket"""
self.logger.debug("Plugin '{}': {}"
.format(self.get_fullname(), message))
@@ -344,6 +339,8 @@ def disconnect(self, message ='disconnecting...'):
def send(self, data):
"""Send data with optional"""
+ if not self.alive:
+ return
try:
self.socket.send(data)
except ConnectionAbortedError as err:
diff --git a/jvcproj/plugin.yaml b/jvcproj/plugin.yaml
index b584191e5..9305f9815 100755
--- a/jvcproj/plugin.yaml
+++ b/jvcproj/plugin.yaml
@@ -10,11 +10,11 @@ plugin:
state: ready
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1188479-plugin-steuerung-von-jvc-d-ila-projektoren
- version: 1.0.1 # Plugin version
- sh_minversion: 1.3 # 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 # plugin supports multi instance
- restartable: unknown
+ multi_instance: false # plugin supports multi instance
+ restartable: true
classname: JVC_DILA_Control # class containing the plugin
parameters:
diff --git a/kostal/__init__.py b/kostal/__init__.py
index b2d00cfcc..f503e0104 100755
--- a/kostal/__init__.py
+++ b/kostal/__init__.py
@@ -21,13 +21,13 @@
#
#########################################################################
-import logging
from lib.model.smartplugin import SmartPlugin
-from lib.utils import Utils
-import urllib.request, json
+import urllib.request
+import json
import time
import re
+
class Kostal(SmartPlugin):
"""
Since UI-version 6 the inverter can answere requests with json.
@@ -37,36 +37,36 @@ class Kostal(SmartPlugin):
"""
ALLOW_MULTIINSTANCE = True
- PLUGIN_VERSION = "1.3.2"
+ PLUGIN_VERSION = "1.3.3"
_key2json = {
- 'operation_status' : 16780032,
- 'dctot_w' : 33556736,
- 'dc1_v' : 33555202,
- 'dc1_a' : 33555201,
- 'dc1_w' : 33555203,
- 'dc2_v' : 33555458,
- 'dc2_a' : 33555457,
- 'dc2_w' : 33555459,
- 'dc3_v' : 33555714,
- 'dc3_a' : 33555713,
- 'dc3_w' : 33555715,
- 'actot_w' : 67109120,
- 'actot_Hz' : 67110400,
- 'actot_cos' : 67110656,
- 'actot_limitation' : 67110144,
- 'ac1_v' : 67109378,
- 'ac1_a' : 67109377,
- 'ac1_w' : 67109379,
- 'ac2_v' : 67109634,
- 'ac2_a' : 67109633,
- 'ac2_w' : 67109635,
- 'ac3_v' : 67109890,
- 'ac3_a' : 67109889,
- 'ac3_w' : 67109891,
- 'yield_day_kwh' : 251658754,
- 'yield_tot_kwh' : 251658753,
- 'operationtime_h' : 251658496
+ 'operation_status': 16780032,
+ 'dctot_w': 33556736,
+ 'dc1_v': 33555202,
+ 'dc1_a': 33555201,
+ 'dc1_w': 33555203,
+ 'dc2_v': 33555458,
+ 'dc2_a': 33555457,
+ 'dc2_w': 33555459,
+ 'dc3_v': 33555714,
+ 'dc3_a': 33555713,
+ 'dc3_w': 33555715,
+ 'actot_w': 67109120,
+ 'actot_Hz': 67110400,
+ 'actot_cos': 67110656,
+ 'actot_limitation': 67110144,
+ 'ac1_v': 67109378,
+ 'ac1_a': 67109377,
+ 'ac1_w': 67109379,
+ 'ac2_v': 67109634,
+ 'ac2_a': 67109633,
+ 'ac2_w': 67109635,
+ 'ac3_v': 67109890,
+ 'ac3_a': 67109889,
+ 'ac3_w': 67109891,
+ 'yield_day_kwh': 251658754,
+ 'yield_tot_kwh': 251658753,
+ 'operationtime_h': 251658496
}
_key2td = {
'actot_w': 9,
@@ -105,25 +105,19 @@ class Kostal(SmartPlugin):
'l3_watt': 'ac3_w'
}
- def __init__(self, sh, ip, user="pvserver", passwd="pvwr",cycle=300, datastructure="html"):
- self._sh = sh
- self.logger = logging.getLogger(__name__)
+ def __init__(self):
+ self.ip = self.get_parameter_value('ip')
+ self.user = self.get_parameter_value('user')
+ self.passwd = self.get_parameter_value('passwd')
+ self.cycle = self.get_parameter_value('cycle')
+ self.datastructure_param = self.get_parameter_value('datastructure')
self.logger.info('Init Kostal plugin')
- self.user = user
- self.passwd = passwd
- self.cycle = int(cycle)
self._items = {}
- if Utils.is_ip(ip):
- self.ip = ip
- else:
- self.logger.error(str(ip) + " is not a valid IP")
- if datastructure == "html":
+ if self.datastructure_param == "html":
self._keytable = self._key2td
- #self.datastructure = "html"
self.datastructure = self._html
else:
self._keytable = self._key2json
- #self.datastructure = "json"
self.datastructure = self._json
def run(self):
@@ -132,13 +126,14 @@ def run(self):
"""
self.logger.debug("run method Kostal called")
self.alive = True
- self._sh.scheduler.add('Kostal', self._refresh, cycle=self.cycle)
+ self.scheduler_add('Kostal', self._refresh, cycle=self.cycle)
def stop(self):
"""
Stop method for the plugin
"""
self.logger.debug("stop method Kostal called")
+ self.scheduler_remove('Kostal')
self.alive = False
def parse_item(self, item):
@@ -155,21 +150,8 @@ def parse_item(self, item):
self._items[setting] = item
return self.update_item
- def parse_logic(self, logic):
- pass
-
- def update_item(self, item, caller=None, source=None, dest=None):
- """
- Write items values
- :param item: item to be updated towards the plugin
- :param caller: if given it represents the callers name
- :param source: if given it represents the source
- :param dest: if given it represents the dest
- """
- pass
-
def _html(self):
- #HTML-OLD-Coding
+ # HTML-OLD-Coding
try:
data = self._sh.tools.fetch_url(
'http://' + self.ip + '/', self.user, self.passwd, timeout=2).decode()
@@ -189,18 +171,18 @@ def _html(self):
return
def _json(self):
- #NEW-JSON-Coding
+ # NEW-JSON-Coding
try:
# generate url; fetching only needed elements
kostalurl = 'http://' + self.ip + '/api/dxs.json?sessionid=SmartHomeNG'
for item in self._items:
value = self._keytable[item]
- kostalurl +='&dxsEntries=' + str(value)
+ kostalurl += '&dxsEntries=' + str(value)
with urllib.request.urlopen(kostalurl) as url:
data = json.loads(url.read().decode())
for values in data['dxsEntries']:
kostal_key = str(list(self._keytable.keys())[list(self._keytable.values()).index(values['dxsId'])])
- value=values['value']
+ value = values['value']
if kostal_key == "operation_status":
self.logger.debug("operation_status" + str(value))
if str(value) == "0":
@@ -214,16 +196,18 @@ def _json(self):
else:
value = "unknown"
if kostal_key == "yield_day_kwh":
- value = value / 1000
+ value = float(value) / 1000
if kostal_key in self._items:
self._items[kostal_key](value)
- self.logger.debug("items[" + str(kostal_key) +"] = " +str(value))
+ self.logger.debug("items[" + str(kostal_key) + "] = " + str(value))
except Exception as e:
self.logger.error(
'could not retrieve data from {0}: {1}'.format(self.ip, e))
return
def _refresh(self):
+ if not self.alive:
+ return
start = time.time()
# run the working methods
self.datastructure()
diff --git a/kostal/plugin.yaml b/kostal/plugin.yaml
index 24d43000e..4e0d5ea70 100755
--- a/kostal/plugin.yaml
+++ b/kostal/plugin.yaml
@@ -27,11 +27,11 @@ plugin:
# documentation: https://github.com/smarthomeNG/smarthome/wiki/CLI-Plugin # url of documentation (wiki) page
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/1109697-kostal-plugin-piko-wechselrichter
- version: 1.3.2 # Plugin version
- sh_minversion: 1.3 # minimum shNG version to use this plugin
+ version: 1.3.3 # 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: True # plugin supports multi instance
- restartable: unknown
+ multi_instance: true # plugin supports multi instance
+ restartable: true
classname: Kostal # class containing the plugin
parameters:
@@ -41,7 +41,7 @@ parameters:
ip:
type: ip
- mandatory: True
+ mandatory: true
description:
de: "IP Adresse des Konverters"
en: "IP address of converter"
diff --git a/luxtronic2/__init__.py b/luxtronic2/__init__.py
index 13cf7b5e5..3116f4e3f 100755
--- a/luxtronic2/__init__.py
+++ b/luxtronic2/__init__.py
@@ -30,6 +30,25 @@
from lib.model.smartplugin import SmartPlugin
+MODES = {
+ 0: 'Heizbetrieb',
+ 1: 'Keine Anforderung',
+ 2: 'Netz- Einschaltverzoegerung',
+ 3: 'SSP Zeit',
+ 4: 'Sperrzeit',
+ 5: 'Brauchwasser',
+ 6: 'Estrich Programm',
+ 7: 'Abtauen',
+ 8: 'Pumpenvorlauf',
+ 9: 'Thermische Desinfektion',
+ 10: 'Kuehlbetrieb',
+ 12: 'Schwimmbad',
+ 13: 'Heizen Ext.',
+ 14: 'Brauchwasser Ext.',
+ 16: 'Durchflussueberwachung',
+ 17: 'ZWE Betrieb'
+}
+
class luxex(Exception):
pass
@@ -233,7 +252,7 @@ def refresh_calculated(self):
class Luxtronic2(LuxBase):
ALLOW_MULTIINSTANCE = False
- PLUGIN_VERSION = '1.3.2'
+ PLUGIN_VERSION = '1.3.3'
_parameter = {}
_attribute = {}
@@ -241,21 +260,22 @@ class Luxtronic2(LuxBase):
_decoded = {}
alive = True
- def __init__(self, smarthome, host, port=8888, cycle=300):
- LuxBase.__init__(self, host, port)
- self._sh = smarthome
- self._cycle = int(cycle)
+ def __init__(self):
+ self._is_connected = False
+ self._cycle = self.get_parameter_value('cycle')
+ LuxBase.__init__(self, self.get_parameter_value('host'), self.get_parameter_value('port'))
self.connect()
def run(self):
self.alive = True
- self._sh.scheduler.add('Luxtronic2', self._refresh, cycle=self._cycle)
+ self.scheduler_add('Luxtronic2', self._refresh, cycle=self._cycle)
def stop(self):
self.alive = False
+ self.scheduler_remove('Luxtronic2')
def _refresh(self):
- if not self.is_connected:
+ if not self.is_connected or not self.alive:
return
start = time.time()
if len(self._parameter) > 0:
@@ -285,54 +305,8 @@ def _refresh(self):
def _decode(self, identifier, value):
if identifier == 119:
- if value == 0:
- return 'Heizbetrieb'
- if value == 1:
- return 'Keine Anforderung'
- if value == 2:
- return 'Netz- Einschaltverzoegerung'
- if value == 3:
- return 'SSP Zeit'
- if value == 4:
- return 'Sperrzeit'
- if value == 5:
- return 'Brauchwasser'
- if value == 6:
- return 'Estrich Programm'
- if value == 7:
- return 'Abtauen'
- if value == 8:
- return 'Pumpenvorlauf'
- if value == 9:
- return 'Thermische Desinfektion'
- if value == 10:
- return 'Kuehlbetrieb'
- if value == 12:
- return 'Schwimmbad'
- if value == 13:
- return 'Heizen Ext.'
- if value == 14:
- return 'Brauchwasser Ext.'
- if value == 16:
- return 'Durchflussueberwachung'
- if value == 17:
- return 'ZWE Betrieb'
- return '???'
- if identifier == 10:
- return float(value) / 10
- if identifier == 11:
- return float(value) / 10
- if identifier == 12:
- return float(value) / 10
- if identifier == 15:
- return float(value) / 10
- if identifier == 19:
- return float(value) / 10
- if identifier == 20:
- return float(value) / 10
- if identifier == 151:
- return float(value) / 10
- if identifier == 152:
+ return MODES.get(value, '???')
+ if identifier in (10, 11, 12, 15, 19, 20, 151, 152):
return float(value) / 10
return value
@@ -356,11 +330,12 @@ def parse_item(self, item):
return self.update_item
def update_item(self, item, caller=None, source=None, dest=None):
- if caller != 'Luxtronic2':
+ if caller != 'Luxtronic2' and self.alive:
self.set_param(self.get_iattr_value(item.conf, 'lux2_p'), item())
def main():
+ lux = None
try:
lux = LuxBase('192.168.178.25')
lux.connect()
@@ -389,5 +364,6 @@ def main():
if lux:
lux.close()
+
if __name__ == "__main__":
sys.exit(main())
diff --git a/luxtronic2/plugin.yaml b/luxtronic2/plugin.yaml
index 1a4349c3d..e98af2d62 100755
--- a/luxtronic2/plugin.yaml
+++ b/luxtronic2/plugin.yaml
@@ -11,11 +11,11 @@ plugin:
# 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
- version: 1.3.2 # Plugin version
+ version: 1.3.3 # Plugin version
sh_minversion: 1.3 # 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: Luxtronic2 # class containing the plugin
parameters:
@@ -32,6 +32,13 @@ parameters:
de: 'Gibt den Port des Gerätes an'
en: 'Specifies the port of the devices'
+ cycle:
+ type: int
+ default: 300
+ description:
+ de: 'Zeitintervall zur Datenabfrage'
+ en: 'Interval for retrieving data'
+
item_attributes:
# Definition of item attributes defined by this plugin
lux2:
diff --git a/plex/__init__.py b/plex/__init__.py
index 37bce2f96..243166afe 100755
--- a/plex/__init__.py
+++ b/plex/__init__.py
@@ -19,7 +19,6 @@
# along with SmartHomeNG. If not, see .
#########################################################################
-import logging
import json
import requests
import random
@@ -27,41 +26,40 @@
class Plex(SmartPlugin):
- PLUGIN_VERSION = "1.0.0"
+ PLUGIN_VERSION = "1.0.1"
ALLOW_MULTIINSTANCE = False
- def __init__(self, smarthome, displaytime=6000):
- self.logger = logging.getLogger(__name__)
+ def __init__(self):
+ self._displayTime = self.get_parameter_value('displaytime')
self.logger.info("Init Plex notifications")
- self._sh = smarthome
- self._displayTime = int(displaytime)
self._images = ["info", "error", "warning"]
self._clients = []
def run(self):
- pass
+ self.alive = True
def stop(self):
- pass
+ self.alive = False
def _push(self, host, data):
- try:
- res = requests.post(host,
- headers={
- "User-Agent": "sh.py",
- "Content-Type": "application/json"},
- timeout=4,
- data=json.dumps(data),
- )
- self.logger.debug(res)
- response = res.text
- del res
- self.logger.debug(response)
- except Exception as e:
- self.logger.exception(e)
+ if self.alive:
+ try:
+ res = requests.post(host,
+ headers={
+ "User-Agent": "sh.py",
+ "Content-Type": "application/json"},
+ timeout=4,
+ data=json.dumps(data),
+ )
+ self.logger.debug(res)
+ response = res.text
+ del res
+ self.logger.debug(response)
+ except Exception as e:
+ self.logger.exception(e)
def notify(self, title, message, image="info"):
- if not image in self._images:
+ if image not in self._images:
self.logger.warn("Plex image must be: {}".format(", ".join(self._images)))
else:
data = {"jsonrpc": "2.0",
diff --git a/plex/plugin.yaml b/plex/plugin.yaml
index 7882ce0c8..302dd0894 100755
--- a/plex/plugin.yaml
+++ b/plex/plugin.yaml
@@ -12,11 +12,11 @@ plugin:
# documentation: https://github.com/smarthomeNG/smarthome/wiki/CLI-Plugin # url of documentation (wiki) page
# support: https://knx-user-forum.de/forum/supportforen/smarthome-py
- version: 1.0.0 # Plugin version
- sh_minversion: 1.1 # minimum shNG version to use this plugin
+ version: 1.0.1 # 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 # plugin supports multi instance
- restartable: unknown
+ multi_instance: false # plugin supports multi instance
+ restartable: true
classname: Plex # class containing the plugin
parameters:
diff --git a/rcswitch/__init__.py b/rcswitch/__init__.py
index 0226ecc3c..389df1fec 100755
--- a/rcswitch/__init__.py
+++ b/rcswitch/__init__.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab
#########################################################################
-# Copyright 2017 Daniel Frank knx-user-forum.de:dafra
+# Copyright 2017 Daniel Frank knx-user-forum.de:dafra
#########################################################################
# This file is part of SmartHomeNG. https://github.com/smarthomeNG//
#
@@ -21,7 +21,6 @@
import logging
from lib.model.smartplugin import SmartPlugin
-from datetime import datetime, timedelta
from socket import gethostname
import time
import threading
@@ -30,105 +29,105 @@
from subprocess import DEVNULL
import shlex
+
class RCswitch(SmartPlugin):
- ALLOW_MULTIINSTANCE = False
- PLUGIN_VERSION = "1.2.2"
+ ALLOW_MULTIINSTANCE = False
+ PLUGIN_VERSION = "1.2.2"
+
+ def __init__(self):
+ self.logger = logging.getLogger(__name__)
+ self.setupOK = True
+ self.mapping = {'a': 1, 'A': 1, 'b': 2, 'B': 2, 'c': 3, 'C': 3, 'd': 4, 'D': 4, 'e': 5, 'E': 5}
+ self.rcswitch_dir = self.get_parameter_value('rcswitch_dir')
+ self.rcswitch_sendDuration = self.get_parameter_value('rcswitch_sendDuration')
+ self.rcswitch_host = self.get_parameter_value('rcswitch_host')
+ self.rcswitch_user = self.get_parameter_value('rcswitch_user')
+ self.rcswitch_password = self.get_parameter_value('rcswitch_password')
+
+ # format path: cut possible '/' at end of rcswitch_dir parameter
+ if self.rcswitch_dir.endswith('/'):
+ self.rcswitch_dir = self.rcswitch_dir[:-1]
+
+ # Handle host, check if anything is defined in self.rcswitch_host parameter and if is valid hostname or valid IPv4 adress
+ if self.rcswitch_host:
+ # then check if user defined its own local host -> error
+ if ((self.rcswitch_host == gethostname()) or (self.rcswitch_host == '127.0.0.1')):
+ self.logger.error('RCswitch: rcswitch_host is defined as your own machine, not the remote address! Please check the parameter rcswitch_host, >>{}<< it seems to be not correct!'.format(self.rcswitch_host))
+
+ # check connection to remote host and accept fingerprint
+ user = None
+ try:
+ # following line shall raise an error in case connection is not possible.
+ user = subprocess.check_output(shlex.split('sshpass -p {} ssh -o StrictHostKeyChecking=no {}@{} grep {} /etc/passwd'.format(self.rcswitch_password, self.rcswitch_user, self.rcswitch_host, self.rcswitch_user)), stderr=DEVNULL).decode('utf8')[:len(self.rcswitch_user)]
+ # check if rc switch is installed at the specified path on remote host
+ self.fileStat = subprocess.check_output(shlex.split('sshpass -p {} ssh {}@{} stat -c %a {}'.format(self.rcswitch_password, self.rcswitch_user, self.rcswitch_host, self.rcswitch_dir)), stderr=DEVNULL).decode('utf8')
+ self.rcswitch_dir = 'sshpass -p {} ssh {}@{} {}'.format(self.rcswitch_password, self.rcswitch_user, self.rcswitch_host, self.rcswitch_dir)
+ self.logger.info('RCswitch: Using {} as host.'.format(self.rcswitch_host))
+ except subprocess.CalledProcessError as e:
+ self.setupOK = False
+ # give user hint where the problem is located
+ try:
+ if (user == self.rcswitch_user):
+ self.logger.error('RCswitch: send file of RCswitch not found at {} on {}. Check if RCswitch is installed correctly at specifed path on {}. System returned: {}'.format(self.rcswitch_dir, self.rcswitch_host, self.rcswitch_host, e))
+ else:
+ self.logger.error('RCswitch: send file of RCswitch not found at {} on {}. Additional problem with user authentication possible. System returned: {}'.format(self.rcswitch_dir, self.rcswitch_host, e))
+ except UnboundLocalError as e:
+ self.logger.error('RCswitch: Cannot connect to {}. Check rcswitch_host, rcswitch_user and rcswitch_password are set (correctly). Ensure SSH server is running on {}. System returned: {}'.format(self.rcswitch_host, self.rcswitch_host, e))
+ else:
+ # check if rc switch is installed at the specified path
+ if not os.path.isfile('{}/send'.format(self.rcswitch_dir)):
+ self.logger.error('RCswitch: send file of RCswitch not found at {} on localhost. Check path, if RCswitch is installed correctly on target, and correct format of v4 IP adress (in case rcswitch_host is defined).'.format(self.rcswitch_dir))
+ self.setupOK = False
+ else:
+ self.logger.info('RCswitch: setup on localhost OK')
- def __init__(self, smarthome, rcswitch_dir='/usr/local/bin/rcswitch-pi', rcswitch_sendDuration='0.5', rcswitch_host=None, rcswitch_user=None, rcswitch_password=None):
- self.logger = logging.getLogger(__name__)
- self.setupOK = True
- self.mapping = {'a':1,'A':1,'b':2,'B':2,'c':3,'C':3,'d':4,'D':4,'e':5,'E':5}
- self._sh = smarthome
-
- # format path: cut possible '/' at end of rcswitch_dir parameter
- if rcswitch_dir[len(rcswitch_dir)-1] == '/':
- self.rcswitch_dir = rcswitch_dir[0:len(rcswitch_dir)-1]
- else:
- self.rcswitch_dir = rcswitch_dir
+ # setup semaphore
+ self.lock = threading.Lock()
- # Check optional Parameters: check sendDuration
- try:
- self.sendDuration = float(rcswitch_sendDuration)
- except Exception as e:
- self.sendDuration = float(0.5)
- self.logger.warning('RCswitch: Argument {} for rcswitch_sendDuration is not a valid number. Using default value instead.'.format(rcswitch_sendDuration))
-
- # Handle host, check if anything is defined in rcswitch_host parameter and if is valid hostname or valid IPv4 adress
- if (rcswitch_host and (self.is_hostname(rcswitch_host) or self.is_ipv4(rcswitch_host))):
- # then check if user defined its own local host -> error
- if ((rcswitch_host == gethostname()) or (rcswitch_host == '127.0.0.1')):
- self.logger.error('RCswitch: rcswitch_host is defined as your own machine, not the remote address! Please check the parameter rcswitch_host, >>{}<< it seems to be not correct!'.format(rcswitch_host))
+ # don't load plugin if init didn't work
+ if not self.setupOK:
+ self._init_complete = False
- #check connection to remote host and accept fingerprint
- try:
- # following line shall raise an error in case connection is not possible.
- self.user = subprocess.check_output(shlex.split('sshpass -p {} ssh -o StrictHostKeyChecking=no {}@{} grep {} /etc/passwd'.format(rcswitch_password, rcswitch_user, rcswitch_host, rcswitch_user)), stderr=DEVNULL).decode('utf8')[0:len(rcswitch_user)]
- # check if rc switch is installed at the specified path on remote host
- self.fileStat = subprocess.check_output(shlex.split('sshpass -p {} ssh {}@{} stat -c %a {}'.format(rcswitch_password, rcswitch_user, rcswitch_host, self.rcswitch_dir)), stderr=DEVNULL).decode('utf8')
- self.rcswitch_dir = ('sshpass -p {} ssh {}@{} {}'.format(rcswitch_password, rcswitch_user, rcswitch_host, self.rcswitch_dir))
- self.logger.info('RCswitch: Using {} as host.'.format(rcswitch_host))
- except subprocess.CalledProcessError as e:
- self.setupOK = False
- # give user hint where the problem is located
- try:
- if (user == rcswitch_user):
- self.logger.error('RCswitch: send file of RCswitch not found at {} on {}. Check if RCswitch is installed correctly at specifed path on {}. System returned: {}'.format(self.rcswitch_dir, rcswitch_host, rcswitch_host, e))
- else:
- self.logger.error('RCswitch: send file of RCswitch not found at {} on {}. Additional problem with user authentication possible. System returned: {}'.format(self.rcswitch_dir, rcswitch_host, e))
- except UnboundLocalError as e:
- self.logger.error('RCswitch: Cannot connect to {}. Check rcswitch_host, rcswitch_user and rcswitch_password are set (correctly). Ensure SSH server is running on {}. System returned: {}'.format(rcswitch_host, rcswitch_host, e))
- else:
- # check if rc switch is installed at the specified path
- if not os.path.isfile('{}/send'.format(self.rcswitch_dir)):
- self.logger.error('RCswitch: send file of RCswitch not found at {} on localhost. Check path, if RCswitch is installed correctly on target, and correct format of v4 IP adress (in case rcswitch_host is defined).'.format(self.rcswitch_dir))
- self.setupOK = False
- else:
- self.logger.info('RCswitch: setup on localhost OK')
-
- # setup semaphore
- self.lock = threading.Lock()
-
- def run(self):
- self.alive = True
+ def run(self):
+ self.alive = True
- def stop(self):
- self.alive = False
+ def stop(self):
+ self.alive = False
- def parse_item(self, item):
- # generate warnings for incomplete configured itemns
- if self.has_iattr(item.conf, 'rc_device'):
- if self.has_iattr(item.conf, 'rc_code'):
- return self.update_item
- else:
- self.logger.warning('RC Switch: attribute rc_code for {} missing. Item will be ignored by RCswitch plugin'.format(item))
- return None
- elif self.has_iattr(item.conf, 'rc_code'):
- self.logger.warning('RC Switch: attribute rc_device for {} missing. Item will be ignored by RCswitch plugin'.format(item))
- return None
- else:
- return None
+ def parse_item(self, item):
+ # generate warnings for incomplete configured itemns
+ if self.has_iattr(item.conf, 'rc_device'):
+ if self.has_iattr(item.conf, 'rc_code'):
+ return self.update_item
+ else:
+ self.logger.warning('RC Switch: attribute rc_code for {} missing. Item will be ignored by RCswitch plugin'.format(item))
+ return None
+ elif self.has_iattr(item.conf, 'rc_code'):
+ self.logger.warning('RC Switch: attribute rc_device for {} missing. Item will be ignored by RCswitch plugin'.format(item))
+ return None
+ else:
+ return None
+ def update_item(self, item, caller=None, source=None, dest=None):
+ # send commands to devices
+ if self.has_iattr(item.conf, 'rc_code') and self.has_iattr(item.conf, 'rc_device') and self.alive:
+ # prepare parameters
+ value = item()
+ rcCode = self.get_iattr_value(item.conf, 'rc_code')
+ rcDevice = self.get_iattr_value(item.conf, 'rc_device')
- def update_item(self, item, caller=None, source=None, dest=None):
- # send commands to devices
- if self.has_iattr(item.conf, 'rc_code') and self.has_iattr(item.conf, 'rc_device') and self.setupOK: #if 'rc_device' in item.conf and 'rc_code' in item.conf and self.setupOK:
- # prepare parameters
- value = item()
- rcCode = self.get_iattr_value(item.conf, 'rc_code')
- rcDevice = self.get_iattr_value(item.conf, 'rc_device')
-
- # avoid parallel access by use of semaphore
- self.lock.acquire()
- # sending commands
- if(rcDevice in self.mapping):#handling of device encoded with a,A,b,...
- subprocess.call(shlex.split('{}/send {} {} {}'.format(self.rcswitch_dir, rcCode, self.mapping[rcDevice], int(value))), stdout=DEVNULL, stderr=DEVNULL)
- self.logger.info('RC Switch: setting device {} with system code {} to {}'.format(rcDevice, rcCode, value))
- else:
- try:#handling of devices encoded with 1,2,3
- subprocess.call(shlex.split('{}/send {} {} {}'.format(self.rcswitch_dir, rcCode, int(rcDevice), int(value))), stdout=DEVNULL, stderr=DEVNULL)
- self.logger.info('RC Switch: setting device {} with system code {} to {}'.format(rcDevice, rcCode, value))
- except Exception as e:#invalid encoding of device
- self.logger.error('RC Switch: requesting invalid device {} with system code {} '.format(rcDevice, rcCode))
- time.sleep(min(self.sendDuration,10))# give the transmitter time to complete sending of the command (but not more than 10s)
- self.lock.release()
\ No newline at end of file
+ # avoid parallel access by use of semaphore
+ self.lock.acquire()
+ # sending commands
+ if (rcDevice in self.mapping): # handling of device encoded with a,A,b,...
+ subprocess.call(shlex.split('{}/send {} {} {}'.format(self.rcswitch_dir, rcCode, self.mapping[rcDevice], int(value))), stdout=DEVNULL, stderr=DEVNULL)
+ self.logger.info('RC Switch: setting device {} with system code {} to {}'.format(rcDevice, rcCode, value))
+ else:
+ try: # handling of devices encoded with 1,2,3
+ subprocess.call(shlex.split('{}/send {} {} {}'.format(self.rcswitch_dir, rcCode, int(rcDevice), int(value))), stdout=DEVNULL, stderr=DEVNULL)
+ self.logger.info('RC Switch: setting device {} with system code {} to {}'.format(rcDevice, rcCode, value))
+ except Exception: # invalid encoding of device
+ self.logger.error('RC Switch: requesting invalid device {} with system code {} '.format(rcDevice, rcCode))
+ time.sleep(min(self.rcswitch_sendDuration, 10)) # give the transmitter time to complete sending of the command (but not more than 10s)
+ self.lock.release()
diff --git a/rcswitch/plugin.yaml b/rcswitch/plugin.yaml
index 65fe7b22b..42b301887 100755
--- a/rcswitch/plugin.yaml
+++ b/rcswitch/plugin.yaml
@@ -13,10 +13,10 @@ plugin:
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/39094-logic-und-howto-für-433mhz-steckdosen
version: 1.2.2 # Plugin version
- sh_minversion: 1.2 # minimum shNG version to use this plugin
+ 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 # plugin supports multi instance
- restartable: unknown
+ multi_instance: false # plugin supports multi instance
+ restartable: true
classname: RCswitch # class containing the plugin
parameters:
From 36d417a1f17b864343c2a86044beffbced6b3a3a Mon Sep 17 00:00:00 2001
From: Morg42 <43153739+Morg42@users.noreply.github.com>
Date: Fri, 24 Nov 2023 13:38:54 +0100
Subject: [PATCH 2/6] fixes
---
helios/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/helios/__init__.py b/helios/__init__.py
index f8c97d53d..b08b0f9f2 100755
--- a/helios/__init__.py
+++ b/helios/__init__.py
@@ -432,10 +432,10 @@ def __init__(self):
def run(self):
self.connect()
self._alive = True
- self._sh.scheduler.add('Helios', self._update, cycle=self._cycle)
+ self.scheduler_add('Helios', self._update, cycle=self._cycle)
def stop(self):
- self._sh.scheduler.remove('Helios')
+ self.scheduler_remove('Helios')
self.disconnect()
self._alive = False
From 39dbee8daa57ebb36ceb176121ff9cbf3dcc34e2 Mon Sep 17 00:00:00 2001
From: Morg42 <43153739+Morg42@users.noreply.github.com>
Date: Fri, 24 Nov 2023 17:39:09 +0100
Subject: [PATCH 3/6] rest of the plugins
---
roomba_980/__init__.py | 55 +++++++++---------
roomba_980/plugin.yaml | 18 +++---
sma/__init__.py | 81 +++++++++++++-------------
sma/plugin.yaml | 18 +++---
smarttv/__init__.py | 24 ++++----
smarttv/plugin.yaml | 18 +++---
sml/__init__.py | 125 +++++++++++++++++++----------------------
sml/plugin.yaml | 8 +--
systemair/__init__.py | 65 ++++++++++-----------
systemair/plugin.yaml | 8 +--
10 files changed, 207 insertions(+), 213 deletions(-)
diff --git a/roomba_980/__init__.py b/roomba_980/__init__.py
index ac2ab99e3..036d1a035 100755
--- a/roomba_980/__init__.py
+++ b/roomba_980/__init__.py
@@ -19,23 +19,23 @@
# along with SmartHome.py. If not, see .
#########################################################################
-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 = {}
@@ -61,7 +61,7 @@ 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
@@ -69,36 +69,35 @@ 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))
diff --git a/roomba_980/plugin.yaml b/roomba_980/plugin.yaml
index 8b9ea3e8e..1da819cd6 100755
--- a/roomba_980/plugin.yaml
+++ b/roomba_980/plugin.yaml
@@ -7,17 +7,17 @@ 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:
@@ -25,28 +25,28 @@ parameters:
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"
diff --git a/sma/__init__.py b/sma/__init__.py
index 2a453c865..82d224a9e 100755
--- a/sma/__init__.py
+++ b/sma/__init__.py
@@ -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
@@ -42,7 +42,6 @@
import socket
from datetime import datetime
from dateutil import tz
-import itertools
from lib.model.smartplugin import SmartPlugin
@@ -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)
@@ -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:
@@ -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)
@@ -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:
@@ -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
@@ -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:
@@ -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])
@@ -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:
@@ -522,7 +523,7 @@ 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):
@@ -530,7 +531,7 @@ def _calc_crc16(self, msg):
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):
@@ -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):
@@ -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)
\ No newline at end of file
+ self._send_msg(msg)
diff --git a/sma/plugin.yaml b/sma/plugin.yaml
index 3bc6bc912..f18e18f74 100755
--- a/sma/plugin.yaml
+++ b/sma/plugin.yaml
@@ -12,18 +12,18 @@ plugin:
documentation: https://smarthomeng.de/user/plugins_doc/config/sma.html # url of documentation (wiki) page
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/27997-beitrag-plugin-zum-lesen-von-sma-wechselrichtern-sunnyboy-5000tl-21-getestet
- version: 1.3.1 # Plugin version
- sh_minversion: 1.3 # minimum shNG version to use this plugin
+ version: 1.3.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 # plugin supports multi instance
- restartable: unknown
+ multi_instance: false # plugin supports multi instance
+ restartable: true
classname: SMA # class containing the plugin
parameters:
# Definition of parameters to be configured in etc/plugin.yaml
bt_addr:
type: str
- mandatory: True
+ mandatory: true
description:
de: 'Bluetooth-Adresse des SMA Wechselrichters (mit "hcitool scan" herauszufinden).'
en: 'Bluetooth address of SMA inverter (find out with "hcitool scan").'
@@ -31,14 +31,14 @@ parameters:
cycle:
type: int
default: 60
- mandatory: False
+ mandatory: false
description:
de: '(optional) Dieser Parameter muss normalerweise nicht angegeben werden. Er erlaubt es die Update-Frquenz anzupassen (Standard: alle 60 Sekunden).'
en: "(optional) This parameter usually doesn't have to be specified. It allows to change the update frequency (cycle every 60 seconds)."
password:
type: str
- mandatory: False
+ mandatory: false
description:
de: '(optional) Passwort des Wechselrichters im User-Mode. Default: 0000.'
en: '(optional) Password of the inverter in user mode. Default: 0000.'
@@ -46,7 +46,7 @@ parameters:
allowed_timedelta:
type: int
default: 10
- mandatory: False
+ mandatory: false
description:
de: '(optional) Erlaubter Zeitunterschied zwischen Systemzeit und Zeit des Wechselrichters. Falls der Inverter auf Systemzeit steht, kann die Prüfung mit -1 deaktiviert werden. Default: 10.'
en: '(optional) Allowed difference of inverter to system time - if above, inverter is set to system time - set to -1 to disable. Default: 10.'
@@ -55,7 +55,7 @@ item_attributes:
# Definition of item attributes defined by this plugin
sma:
type: str
- mandatory: True
+ mandatory: true
description:
de: 'Auszulesender Wert, möglich sind: PLUGIN_ACTIVE, AC_P_TOTAL, E_DAY, E_TOTAL, INV_SERIAL, INV_ADDRESS, LAST_UPDATE, DC_STRING1_P, DC_STRING2_P, DC_STRING1_U, DC_STRING2_U, DC_STRING1_I, DC_STRING2_I, OPERATING_TIME, FEEDING_TIME, GRID_FREQUENCY, STATUS, GRID_RELAY, SW_VERSION.'
en: 'Value to read. Possible: PLUGIN_ACTIVE, AC_P_TOTAL, E_DAY, E_TOTAL, INV_SERIAL, INV_ADDRESS, LAST_UPDATE, DC_STRING1_P, DC_STRING2_P, DC_STRING1_U, DC_STRING2_U, DC_STRING1_I, DC_STRING2_I, OPERATING_TIME, FEEDING_TIME, GRID_FREQUENCY, STATUS, GRID_RELAY, SW_VERSION.'
diff --git a/smarttv/__init__.py b/smarttv/__init__.py
index 07dde2fc5..654f13475 100755
--- a/smarttv/__init__.py
+++ b/smarttv/__init__.py
@@ -27,21 +27,23 @@
from lib.model.smartplugin import SmartPlugin
from uuid import getnode as getmac
+
class SmartTV(SmartPlugin):
ALLOW_MULTIINSTANCE = True
- PLUGIN_VERSION = "1.3.2"
+ PLUGIN_VERSION = "1.3.3"
- def __init__(self, smarthome, host, port=55000, tv_version='classic', delay=1):
+ def __init__(self):
self.logger = logging.getLogger(__name__)
- self._sh = smarthome
- self._host = host
- self._port = int(port)
- self._delay = delay
- if tv_version not in ['samsung_m_series', 'classic']:
+ self._tv_version = self.get_parameter_value('tv_version')
+ self._host = self.get_parameter_value('host')
+ self._port = self.get_parameter_value('port')
+ self._delay = self.get_parameter_value('delay')
+ if self._tv_version not in ['samsung_m_series', 'classic']:
self.logger.error('No valid tv_version attribute specified to plugin')
- self._tv_version = tv_version
- self.logger.debug("Smart TV plugin for {0} SmartTV device initalized".format(tv_version))
+ self._init_complete = False
+ else:
+ self.logger.debug("Smart TV plugin for {0} SmartTV device initalized".format(self._tv_version))
def push_samsung_m_series(self, key):
"""
@@ -68,7 +70,7 @@ def push_classic(self, key):
self.logger.debug("Connected to {0}:{1}".format(self._host, self._port))
except Exception:
self.logger.warning("Could not connect to %s:%s, to send key: %s." %
- (self._host, self._port, key))
+ (self._host, self._port, key))
return
src = s.getsockname()[0] # ip of remote
@@ -140,6 +142,8 @@ def parse_item(self, item):
return None
def update_item(self, item, caller=None, source=None, dest=None):
+ if not self.alive:
+ return
val = item()
if isinstance(val, str):
if val.startswith('KEY_'):
diff --git a/smarttv/plugin.yaml b/smarttv/plugin.yaml
index ef43b482d..8127d8b16 100755
--- a/smarttv/plugin.yaml
+++ b/smarttv/plugin.yaml
@@ -12,25 +12,25 @@ plugin:
# documentation: https://github.com/smarthomeNG/smarthome/wiki/CLI-Plugin # url of documentation (wiki) page
# support: https://knx-user-forum.de/forum/supportforen/smarthome-py
- version: 1.3.2 # Plugin version
- sh_minversion: 1.3 # minimum shNG version to use this plugin
+ version: 1.3.3 # 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: True # plugin supports multi instance
- restartable: unknown
+ multi_instance: true # plugin supports multi instance
+ restartable: true
classname: SmartTV # class containing the plugin
parameters:
# Definition of parameters to be configured in etc/plugin.yaml
host:
type: str
- mandatory: True
+ mandatory: true
description:
de: 'IP Adresse des SmartTV Geräts.'
en: 'Specifies the ip address of your SmartTV device.'
port:
type: int
- mandatory: False
+ mandatory: false
default: 55000
description:
de: '(optional) Im Fall eines Ports zu setzen, der nicht dem Standard entspricht (Standardports siehe tv_version). Default: 55000.'
@@ -38,7 +38,7 @@ parameters:
tv_version:
type: str
- mandatory: False
+ mandatory: false
default: classic
description:
de: '(optional) Erlaubte Werte sind "classic" (Port 55000) oder "samsung_m_series" (Standardport: 8001). Default: "classic".'
@@ -46,7 +46,7 @@ parameters:
delay:
type: int
- mandatory: False
+ mandatory: false
default: 1
description:
de: '(optional) Verzögerung in Sekunden, falls mehr als eine Taste gesendet wird. Reduziert Probleme, wenn bspw. TV-Programme wie "135" aufgerufen werden. Default: 1'
@@ -57,7 +57,7 @@ item_attributes:
# Definition of item attributes defined by this plugin
smarttv:
type: str
- mandatory: True
+ mandatory: true
description:
de: 'Es gibt zwei Wege das Attribut zu nutzen.
* Auf einem Item des Typs `str` mit dem Wert "true": Jeder String der in das Item geschrieben wird, wird an den SmartTV gesendet.
diff --git a/sml/__init__.py b/sml/__init__.py
index aabb788d9..2e93df094 100755
--- a/sml/__init__.py
+++ b/sml/__init__.py
@@ -32,31 +32,32 @@
from lib.model.smartplugin import SmartPlugin
+
class Sml(SmartPlugin):
ALLOW_MULTIINSTANCE = True
- PLUGIN_VERSION = '1.0.0'
+ PLUGIN_VERSION = '1.0.1'
_v1_start = b'\x1b\x1b\x1b\x1b\x01\x01\x01\x01'
_v1_end = b'\x1b\x1b\x1b\x1b\x1a'
_units = { # Blue book @ http://www.dlms.com/documentation/overviewexcerptsofthedlmsuacolouredbooks/index.html
- 1 : 'a', 2 : 'mo', 3 : 'wk', 4 : 'd', 5 : 'h', 6 : 'min.', 7 : 's', 8 : '°', 9 : '°C', 10 : 'currency',
- 11 : 'm', 12 : 'm/s', 13 : 'm³', 14 : 'm³', 15 : 'm³/h', 16 : 'm³/h', 17 : 'm³/d', 18 : 'm³/d', 19 : 'l', 20 : 'kg',
- 21 : 'N', 22 : 'Nm', 23 : 'Pa', 24 : 'bar', 25 : 'J', 26 : 'J/h', 27 : 'W', 28 : 'VA', 29 : 'var', 30 : 'Wh',
- 31 : 'WAh', 32 : 'varh', 33 : 'A', 34 : 'C', 35 : 'V', 36 : 'V/m', 37 : 'F', 38 : 'Ω', 39 : 'Ωm²/h', 40 : 'Wb',
- 41 : 'T', 42 : 'A/m', 43 : 'H', 44 : 'Hz', 45 : 'Rac', 46 : 'Rre', 47 : 'Rap', 48 : 'V²h', 49 : 'A²h', 50 : 'kg/s',
- 51 : 'Smho'
+ 1: 'a', 2: 'mo', 3: 'wk', 4: 'd', 5: 'h', 6: 'min.', 7: 's', 8: '°', 9: '°C', 10: 'currency',
+ 11: 'm', 12: 'm/s', 13: 'm³', 14: 'm³', 15: 'm³/h', 16: 'm³/h', 17: 'm³/d', 18: 'm³/d', 19: 'l', 20: 'kg',
+ 21: 'N', 22: 'Nm', 23: 'Pa', 24: 'bar', 25: 'J', 26: 'J/h', 27: 'W', 28: 'VA', 29: 'var', 30: 'Wh',
+ 31: 'WAh', 32: 'varh', 33: 'A', 34: 'C', 35: 'V', 36: 'V/m', 37: 'F', 38: 'Ω', 39: 'Ωm²/h', 40: 'Wb',
+ 41: 'T', 42: 'A/m', 43: 'H', 44: 'Hz', 45: 'Rac', 46: 'Rre', 47: 'Rap', 48: 'V²h', 49: 'A²h', 50: 'kg/s',
+ 51: 'Smho'
}
_devices = {
- 'smart-meter-gateway-com-1' : 'hex'
+ 'smart-meter-gateway-com-1': 'hex'
}
- def __init__(self, smarthome, host=None, port=0, serialport=None, device="raw", cycle=300):
- self._sh = smarthome
- self.host = host
- self.port = int(port)
- self.serialport = serialport
- self.cycle = cycle
+ def __init__(self):
+ self.host = self.get_parameter_value('host')
+ self.port = self.get_parameter_value('port')
+ self.serialport = self.get_parameter_value('serialport')
+ self.cycle = self.get_parameter_value('cycle')
+ self.device = self.get_parameter_value('device')
self.connected = False
self._serial = None
self._sock = None
@@ -66,23 +67,24 @@ def __init__(self, smarthome, host=None, port=0, serialport=None, device="raw",
self._lock = threading.Lock()
self.logger = logging.getLogger(__name__)
- if device in self._devices:
- device = self._devices[device]
+ if self._device in self._devices:
+ self._device = self._devices[self._device]
- if device == "hex":
+ if self._device == "hex":
self._prepare = self._prepareHex
- elif device == "raw":
+ elif self._device == "raw":
self._prepare = self._prepareRaw
else:
- self.logger.warning("Device type \"{}\" not supported - defaulting to \"raw\"".format(device))
+ self.logger.warning("Device type \"{}\" not supported - defaulting to \"raw\"".format(self._device))
self._prepare = self._prepareRaw
def run(self):
self.alive = True
- self._sh.scheduler.add('Sml', self._refresh, cycle=self.cycle)
+ self.scheduler_add('Sml', self._refresh, cycle=self.cycle)
def stop(self):
self.alive = False
+ self.scheduler_remove('Sml')
self.disconnect()
def parse_item(self, item):
@@ -98,16 +100,8 @@ def parse_item(self, item):
return self.update_item
return None
- def parse_logic(self, logic):
- pass
-
- def update_item(self, item, caller=None, source=None, dest=None):
- if caller != 'Sml':
- pass
-
def connect(self):
self._lock.acquire()
- target = None
try:
if self.serialport is not None:
self._target = 'serial://{}'.format(self.serialport)
@@ -164,9 +158,9 @@ def _read(self, length):
raise e
return b''.join(total)
-
+
def _refresh(self):
- if self.connected:
+ if self.connected and self.alive:
start = time.time()
retry = 5
data = None
@@ -183,8 +177,8 @@ def _refresh(self):
if start_pos != -1 and end_pos == -1:
data = data[:start_pos]
elif start_pos != -1 and end_pos != -1:
- chunk = data[start_pos:end_pos+len(self._v1_end)+3]
- self.logger.debug('Found chunk at {} - {} ({} bytes):{}'.format(start_pos, end_pos, end_pos-start_pos, ''.join(' {:02x}'.format(x) for x in chunk)))
+ chunk = data[start_pos:end_pos + len(self._v1_end) + 3]
+ self.logger.debug('Found chunk at {} - {} ({} bytes):{}'.format(start_pos, end_pos, end_pos - start_pos, ''.join(' {:02x}'.format(x) for x in chunk)))
chunk_crc_str = '{:02X}{:02X}'.format(chunk[-2], chunk[-1])
chunk_crc_calc = self._crc16(chunk[:-2])
chunk_crc_calc_str = '{:02X}{:02X}'.format((chunk_crc_calc >> 8) & 0xff, chunk_crc_calc & 0xff)
@@ -236,27 +230,27 @@ def _parse(self, data):
packetsize = 7
self.logger.debug('Data ({} bytes):{}'.format(len(data), ''.join(' {:02x}'.format(x) for x in data)))
self._dataoffset = 0
- while self._dataoffset < builtins.len(data)-packetsize:
+ while self._dataoffset < builtins.len(data) - packetsize:
# Find SML_ListEntry starting with 0x77 0x07 and OBIS code end with 0xFF
- if data[self._dataoffset] == 0x77 and data[self._dataoffset+1] == 0x07 and data[self._dataoffset+packetsize] == 0xff:
+ if data[self._dataoffset] == 0x77 and data[self._dataoffset + 1] == 0x07 and data[self._dataoffset + packetsize] == 0xff:
packetstart = self._dataoffset
self._dataoffset += 1
try:
entry = {
- 'objName' : self._read_entity(data),
- 'status' : self._read_entity(data),
- 'valTime' : self._read_entity(data),
- 'unit' : self._read_entity(data),
- 'scaler' : self._read_entity(data),
- 'value' : self._read_entity(data),
- 'signature' : self._read_entity(data)
+ 'objName': self._read_entity(data),
+ 'status': self._read_entity(data),
+ 'valTime': self._read_entity(data),
+ 'unit': self._read_entity(data),
+ 'scaler': self._read_entity(data),
+ 'value': self._read_entity(data),
+ 'signature': self._read_entity(data)
}
# add additional calculated fields
entry['obis'] = '{}-{}:{}.{}.{}*{}'.format(entry['objName'][0], entry['objName'][1], entry['objName'][2], entry['objName'][3], entry['objName'][4], entry['objName'][5])
entry['valueReal'] = entry['value'] * 10 ** entry['scaler'] if entry['scaler'] is not None else entry['value']
- entry['unitName'] = self._units[entry['unit']] if entry['unit'] != None and entry['unit'] in self._units else None
+ entry['unitName'] = self._units[entry['unit']] if entry['unit'] is not None and entry['unit'] in self._units else None
values[entry['obis']] = entry
except Exception as e:
@@ -269,8 +263,8 @@ def _parse(self, data):
def _read_entity(self, data):
upack = {
- 5 : { 1 : '>b', 2 : '>h', 4 : '>i', 8 : '>q' }, # int
- 6 : { 1 : '>B', 2 : '>H', 4 : '>I', 8 : '>Q' } # uint
+ 5: {1: '>b', 2: '>h', 4: '>i', 8: '>q'}, # int
+ 6: {1: '>B', 2: '>H', 4: '>I', 8: '>Q'} # uint
}
result = None
@@ -296,23 +290,23 @@ def _read_entity(self, data):
self._parse_error('Tried to read {} bytes, but only have {}', [len, builtins.len(data) - self._dataoffset], data, self._dataoffset, packetstart)
elif type == 0: # octet string
- result = data[self._dataoffset:self._dataoffset+len]
+ result = data[self._dataoffset:self._dataoffset + len]
elif type == 5 or type == 6: # int or uint
- d = data[self._dataoffset:self._dataoffset+len]
+ d = data[self._dataoffset:self._dataoffset + len]
ulen = len
if ulen not in upack[type]: # extend to next greather unpack unit
- while ulen not in upack[type]:
- d = b'\x00' + d
- ulen += 1
+ while ulen not in upack[type]:
+ d = b'\x00' + d
+ ulen += 1
result = struct.unpack(upack[type][ulen], d)[0]
elif type == 7: # list
result = []
self._dataoffset += 1
- for i in range(0, len + 1):
+ for _ in range(0, len + 1):
result.append(self._read_entity(data))
return result
@@ -326,7 +320,7 @@ def _read_entity(self, data):
def _parse_error(self, msg, msgargs, data, dataoffset, packetstart):
position = dataoffset - packetstart
databytes = ''
- for i, b in enumerate(data[packetstart:packetstart+64]):
+ for i, b in enumerate(data[packetstart:packetstart + 64]):
databytes = databytes + ' {}{:02x}{}'.format(
'' if i != position - 1 else '<',
b,
@@ -348,24 +342,23 @@ def _prepareHex(self, data):
data = re.sub("[^a-f0-9]", " ", data)
data = re.sub("( +[a-f0-9]|[a-f0-9] +)", "", data)
data = data.encode()
- return bytes(''.join(chr(int(data[i:i+2], 16)) for i in range(0, len(data), 2)), "iso8859-1")
+ return bytes(''.join(chr(int(data[i:i + 2], 16)) for i in range(0, len(data), 2)), "iso8859-1")
def _crc16(self, data):
- crc = 0xffff
-
- p = 0;
- while p < len(data):
- c = 0xff & data[p]
- p = p + 1
+ crc = 0xffff
- for i in range(0, 8):
- if ((crc & 0x0001) ^ (c & 0x0001)):
- crc = (crc >> 1) ^ 0x8408
- else:
- crc = crc >> 1
- c = c >> 1
+ p = 0
+ while p < len(data):
+ c = 0xff & data[p]
+ p = p + 1
- crc = ~crc & 0xffff
+ for i in range(0, 8):
+ if ((crc & 0x0001) ^ (c & 0x0001)):
+ crc = (crc >> 1) ^ 0x8408
+ else:
+ crc = crc >> 1
+ c = c >> 1
- return ((crc << 8) | ((crc >> 8) & 0xff)) & 0xffff
+ crc = ~crc & 0xffff
+ return ((crc << 8) | ((crc >> 8) & 0xff)) & 0xffff
diff --git a/sml/plugin.yaml b/sml/plugin.yaml
index 91360c5b2..c031f5e10 100755
--- a/sml/plugin.yaml
+++ b/sml/plugin.yaml
@@ -12,11 +12,11 @@ plugin:
documentation: http://smarthomeng.de/user/plugins_doc/config/sml.html
# support: https://knx-user-forum.de/forum/supportforen/smarthome-py
- version: 1.0.0 # Plugin version
- sh_minversion: 1.1 # minimum shNG version to use this plugin
+ version: 1.0.1 # 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: True # plugin supports multi instance
- restartable: unknown
+ multi_instance: true # plugin supports multi instance
+ restartable: true
classname: Sml # class containing the plugin
parameters:
diff --git a/systemair/__init__.py b/systemair/__init__.py
index dc467c6ee..24a40b8e5 100755
--- a/systemair/__init__.py
+++ b/systemair/__init__.py
@@ -18,50 +18,47 @@
# You should have received a copy of the GNU General Public License
# along with this plugin. If not, see .
#########################################################################
-import logging
from time import sleep
import minimalmodbus
-from serial import SerialException
import serial
import threading
from ctypes import c_short
from lib.model.smartplugin import SmartPlugin
+
class Systemair(SmartPlugin):
- PLUGIN_VERSION = "1.3.0.1"
+ PLUGIN_VERSION = "1.3.1"
ALLOW_MULTIINSTANCE = False
- def __init__(self, smarthome, serialport, slave_address="1", update_cycle="30"):
- self._sh = smarthome
- self.logger = logging.getLogger(__name__)
+ def __init__(self):
self.instrument = None
- self.slave_address = int(slave_address)
+ self.serialport = self.get_parameter_value('serialport')
+ self.slave_address = self.get_parameter_value('slave_address')
+ self._update_cycle = self.get_parameter_value('update_cycle')
self._update_coil = {}
- self.serialport = serialport
- self.slave_address = slave_address
minimalmodbus.TIMEOUT = 3
- minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL=True
- self._sh.scheduler.add(__name__, self._read_modbus, prio=5, cycle=int(update_cycle))
+ minimalmodbus.CLOSE_PORT_AFTER_EACH_CALL = True
+ self.scheduler_add(__name__, self._read_modbus, prio=5, cycle=self._update_cycle)
self.my_reg_items = []
self.mod_write_repeat = 20 # if port is already open, e.g on auto-update,
# repeat mod_write attempt x times a 1 seconds
self._lockmb = threading.Lock() # modbus serial port lock
self.init_serial_connection(self.serialport, self.slave_address)
- self._reg_sets = [{'name':'fan', 'range':range(101, 138+1)},
- {'name':'heater', 'range':range(201, 221+1), 'scaled_signed':range(208, 218+1)},
- {'name':'damper', 'range':range(301, 301+1)},
- {'name':'rotor', 'range':range(351, 352+1)},
- {'name':'week', 'range':range(401, 459+1)},
- {'name':'system', 'range':range(501, 507+1)},
- {'name':'clock', 'range':range(551, 557+1)},
- {'name':'filter', 'range':range(601, 602+1)},
- {'name':'VTC_defr', 'range':range(651, 654+1)},
- {'name':'VTR_defr', 'range':range(671, 672+1)},
- {'name':'dig_in', 'range':range(701, 709+1)},
- {'name':'PCU_PB', 'range':range(751, 751+1)},
- {'name':'alarms', 'range':range(801, 802+1)},
- {'name':'demand', 'range':range(851, 859+1)},
- {'name':'wireless', 'range':range(901, 1020+1)},]
+ self._reg_sets = [{'name': 'fan', 'range': range(101, 138 + 1)},
+ {'name': 'heater', 'range': range(201, 221 + 1), 'scaled_signed': range(208, 218 + 1)},
+ {'name': 'damper', 'range': range(301, 301 + 1)},
+ {'name': 'rotor', 'range': range(351, 352 + 1)},
+ {'name': 'week', 'range': range(401, 459 + 1)},
+ {'name': 'system', 'range': range(501, 507 + 1)},
+ {'name': 'clock', 'range': range(551, 557 + 1)},
+ {'name': 'filter', 'range': range(601, 602 + 1)},
+ {'name': 'VTC_defr', 'range': range(651, 654 + 1)},
+ {'name': 'VTR_defr', 'range': range(671, 672 + 1)},
+ {'name': 'dig_in', 'range': range(701, 709 + 1)},
+ {'name': 'PCU_PB', 'range': range(751, 751 + 1)},
+ {'name': 'alarms', 'range': range(801, 802 + 1)},
+ {'name': 'demand', 'range': range(851, 859 + 1)},
+ {'name': 'wireless', 'range': range(901, 1020 + 1)},]
def init_serial_connection(self, serialport, slave_address):
try:
@@ -84,9 +81,9 @@ def _read_modbus(self):
for reg_set in self._reg_sets:
if 'range_used' in reg_set:
read_regs = dict(zip(reg_set['range_used'], self.instrument.read_registers(
- reg_set['range_used'].start -1,
- reg_set['range_used'].stop - reg_set['range_used'].start,
- functioncode = 3)))
+ reg_set['range_used'].start - 1,
+ reg_set['range_used'].stop - reg_set['range_used'].start,
+ functioncode=3)))
if 'scaled_signed' in reg_set:
for scaled_reg in reg_set['scaled_signed']:
read_regs[scaled_reg] = c_short(read_regs[scaled_reg]).value / 10
@@ -100,7 +97,7 @@ def _read_modbus(self):
# get coils
for coil_addr in self._update_coil:
- value = self.instrument.read_bit(coil_addr-1, functioncode=2)
+ value = self.instrument.read_bit(coil_addr - 1, functioncode=2)
if value is not None:
for item in self._update_coil[coil_addr]:
item(value, 'systemair_value_from_bus', "Coil {}".format(coil_addr))
@@ -123,7 +120,7 @@ def connect(self):
def update_item(self, item, caller=None, source=None, dest=None):
# ignore values from bus
- if caller == 'systemair_value_from_bus':
+ if caller == 'systemair_value_from_bus' or not self.alive:
return
if item in self.my_reg_items:
if self.has_iattr(item.conf, 'mod_write'):
@@ -138,9 +135,9 @@ def parse_item(self, item):
for reg_set in self._reg_sets:
if modbus_regaddr in reg_set['range']:
- if not 'regs_used' in reg_set:
+ if 'regs_used' not in reg_set:
reg_set['regs_used'] = dict()
- if not modbus_regaddr in reg_set['regs_used']:
+ if modbus_regaddr not in reg_set['regs_used']:
reg_set['regs_used'][modbus_regaddr] = set()
reg_set['regs_used'][modbus_regaddr].add(item)
@@ -155,7 +152,7 @@ def parse_item(self, item):
if self.has_iattr(item.conf, 'systemair_coiladdr'):
modbus_coiladdr = int(self.get_iattr_value(item.conf, 'systemair_coiladdr'))
self.logger.debug("systemair_value_from_bus: {0} connected to coil register {1:#04x}".format(item, modbus_coiladdr))
- if not modbus_coiladdr in self._update_coil:
+ if modbus_coiladdr not in self._update_coil:
self._update_coil[modbus_coiladdr] = set()
self._update_coil[modbus_coiladdr].add(item)
diff --git a/systemair/plugin.yaml b/systemair/plugin.yaml
index b1979bc82..98e015e4d 100755
--- a/systemair/plugin.yaml
+++ b/systemair/plugin.yaml
@@ -12,11 +12,11 @@ plugin:
# documentation: https://github.com/smarthomeNG/smarthome/wiki/CLI-Plugin # url of documentation (wiki) page
support: https://knx-user-forum.de/forum/supportforen/smarthome-py/939623-systemair-modbus-plugin-zentrale-lüftungsanlage
- version: 1.3.0.1 # Plugin version
- sh_minversion: 1.3 # minimum shNG version to use this plugin
+ version: 1.3.1 # 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 # plugin supports multi instance
- restartable: unknown
+ multi_instance: false # plugin supports multi instance
+ restartable: true
classname: Systemair # class containing the plugin
parameters:
From 3fcbe8329a98cc7d545e32d5947c6a57113da61f Mon Sep 17 00:00:00 2001
From: Morg42 <43153739+Morg42@users.noreply.github.com>
Date: Fri, 24 Nov 2023 18:04:19 +0100
Subject: [PATCH 4/6] fix init parameters
---
comfoair/__init__.py | 2 +-
intercom_2n/__init__.py | 2 +-
jvcproj/__init__.py | 2 +-
kostal/__init__.py | 2 +-
luxtronic2/__init__.py | 4 ++--
plex/__init__.py | 2 +-
rcswitch/__init__.py | 2 +-
roomba_980/__init__.py | 2 +-
sma/__init__.py | 2 +-
smarttv/__init__.py | 2 +-
sml/__init__.py | 2 +-
systemair/__init__.py | 2 +-
12 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/comfoair/__init__.py b/comfoair/__init__.py
index 5196fff66..4e72f9eb2 100755
--- a/comfoair/__init__.py
+++ b/comfoair/__init__.py
@@ -33,7 +33,7 @@ class ComfoAir(SmartPlugin):
ALLOW_MULTIINSTANCE = False
PLUGIN_VERSION = '1.3.1'
- def __init__(self):
+ def __init__(self, **kwargs):
self.logger = logging.getLogger('ComfoAir')
self.connected = False
self._params = {}
diff --git a/intercom_2n/__init__.py b/intercom_2n/__init__.py
index a859fe667..1c785e053 100755
--- a/intercom_2n/__init__.py
+++ b/intercom_2n/__init__.py
@@ -36,7 +36,7 @@ class Intercom2n(SmartPlugin):
PLUGIN_VERSION = "1.3.1"
ALLOW_MULTIINSTANCE = False
- def __init__(self):
+ def __init__(self, **kwargs):
self._intercom_ip = self.get_parameter_value('intercom_ip')
self._ssl = self.get_parameter_value('ssl')
self._auth_type = self.get_parameter_value('auth_type')
diff --git a/jvcproj/__init__.py b/jvcproj/__init__.py
index c907cc622..649cea506 100755
--- a/jvcproj/__init__.py
+++ b/jvcproj/__init__.py
@@ -99,7 +99,7 @@ class JVC_DILA_Control(SmartPlugin):
ALLOW_MULTIINSTANCE = False
PLUGIN_VERSION = '1.0.2'
- def __init__(self):
+ def __init__(self, **kwargs):
"""
Initalizes the plugin. The parameters describe for this method are pulled from the entry in plugin.conf.
:param host: JVC DILA Projectors IP address
diff --git a/kostal/__init__.py b/kostal/__init__.py
index f503e0104..ffc2ab3bf 100755
--- a/kostal/__init__.py
+++ b/kostal/__init__.py
@@ -105,7 +105,7 @@ class Kostal(SmartPlugin):
'l3_watt': 'ac3_w'
}
- def __init__(self):
+ def __init__(self, **kwargs):
self.ip = self.get_parameter_value('ip')
self.user = self.get_parameter_value('user')
self.passwd = self.get_parameter_value('passwd')
diff --git a/luxtronic2/__init__.py b/luxtronic2/__init__.py
index 3116f4e3f..1d0dee433 100755
--- a/luxtronic2/__init__.py
+++ b/luxtronic2/__init__.py
@@ -58,7 +58,7 @@ class LuxBase(SmartPlugin):
# ATTENTION: This is NOT the SmartPlugin class of the plugin!!!
- def __init__(self, host, port=8888):
+ def __init__(self, host, port=8888, **kwargs):
self.logger = logging.getLogger(__name__)
self.host = host
self.port = int(port)
@@ -260,7 +260,7 @@ class Luxtronic2(LuxBase):
_decoded = {}
alive = True
- def __init__(self):
+ def __init__(self, **kwargs):
self._is_connected = False
self._cycle = self.get_parameter_value('cycle')
LuxBase.__init__(self, self.get_parameter_value('host'), self.get_parameter_value('port'))
diff --git a/plex/__init__.py b/plex/__init__.py
index 243166afe..b21159f38 100755
--- a/plex/__init__.py
+++ b/plex/__init__.py
@@ -29,7 +29,7 @@ class Plex(SmartPlugin):
PLUGIN_VERSION = "1.0.1"
ALLOW_MULTIINSTANCE = False
- def __init__(self):
+ def __init__(self, **kwargs):
self._displayTime = self.get_parameter_value('displaytime')
self.logger.info("Init Plex notifications")
self._images = ["info", "error", "warning"]
diff --git a/rcswitch/__init__.py b/rcswitch/__init__.py
index 389df1fec..0198b4321 100755
--- a/rcswitch/__init__.py
+++ b/rcswitch/__init__.py
@@ -35,7 +35,7 @@ class RCswitch(SmartPlugin):
ALLOW_MULTIINSTANCE = False
PLUGIN_VERSION = "1.2.2"
- def __init__(self):
+ def __init__(self, **kwargs):
self.logger = logging.getLogger(__name__)
self.setupOK = True
self.mapping = {'a': 1, 'A': 1, 'b': 2, 'B': 2, 'c': 3, 'C': 3, 'd': 4, 'D': 4, 'e': 5, 'E': 5}
diff --git a/roomba_980/__init__.py b/roomba_980/__init__.py
index 036d1a035..b43738a7f 100755
--- a/roomba_980/__init__.py
+++ b/roomba_980/__init__.py
@@ -31,7 +31,7 @@ class ROOMBA_980(SmartPlugin):
myroomba = None
- def __init__(self):
+ def __init__(self, **kwargs):
self._address = self.get_parameter_value('adress')
self._blid = self.get_parameter_value('blid')
self._roombaPassword = self.get_parameter_value('roombaPassword')
diff --git a/sma/__init__.py b/sma/__init__.py
index 82d224a9e..a70879e32 100755
--- a/sma/__init__.py
+++ b/sma/__init__.py
@@ -186,7 +186,7 @@ class SMA(SmartPlugin):
ALLOW_MULTIINSTANCE = False
PLUGIN_VERSION = "1.3.2"
- def __init__(self):
+ def __init__(self, **kwargs):
# TODO: self._own_bt_addr setzen
self.logger = logging.getLogger(__name__)
self._inv_bt_addr = self.get_parameter_value('bt_addr')
diff --git a/smarttv/__init__.py b/smarttv/__init__.py
index 654f13475..bb90f1a44 100755
--- a/smarttv/__init__.py
+++ b/smarttv/__init__.py
@@ -33,7 +33,7 @@ class SmartTV(SmartPlugin):
ALLOW_MULTIINSTANCE = True
PLUGIN_VERSION = "1.3.3"
- def __init__(self):
+ def __init__(self, **kwargs):
self.logger = logging.getLogger(__name__)
self._tv_version = self.get_parameter_value('tv_version')
self._host = self.get_parameter_value('host')
diff --git a/sml/__init__.py b/sml/__init__.py
index 2e93df094..b1eb80af4 100755
--- a/sml/__init__.py
+++ b/sml/__init__.py
@@ -52,7 +52,7 @@ class Sml(SmartPlugin):
'smart-meter-gateway-com-1': 'hex'
}
- def __init__(self):
+ def __init__(self, **kwargs):
self.host = self.get_parameter_value('host')
self.port = self.get_parameter_value('port')
self.serialport = self.get_parameter_value('serialport')
diff --git a/systemair/__init__.py b/systemair/__init__.py
index 24a40b8e5..df353ccea 100755
--- a/systemair/__init__.py
+++ b/systemair/__init__.py
@@ -30,7 +30,7 @@ class Systemair(SmartPlugin):
PLUGIN_VERSION = "1.3.1"
ALLOW_MULTIINSTANCE = False
- def __init__(self):
+ def __init__(self, **kwargs):
self.instrument = None
self.serialport = self.get_parameter_value('serialport')
self.slave_address = self.get_parameter_value('slave_address')
From 6fb4ee30a950c54f7327be07e8fbd29b5b143531 Mon Sep 17 00:00:00 2001
From: Morg42 <43153739+Morg42@users.noreply.github.com>
Date: Sun, 26 Nov 2023 16:55:57 +0100
Subject: [PATCH 5/6] remove unnecessary logging setup
---
comfoair/__init__.py | 2 --
sma/__init__.py | 2 --
sml/__init__.py | 2 --
3 files changed, 6 deletions(-)
diff --git a/comfoair/__init__.py b/comfoair/__init__.py
index 4e72f9eb2..382495e72 100755
--- a/comfoair/__init__.py
+++ b/comfoair/__init__.py
@@ -18,7 +18,6 @@
# along with this plugin. If not, see .
#########################################################################
-import logging
import socket
import time
import serial
@@ -34,7 +33,6 @@ class ComfoAir(SmartPlugin):
PLUGIN_VERSION = '1.3.1'
def __init__(self, **kwargs):
- self.logger = logging.getLogger('ComfoAir')
self.connected = False
self._params = {}
self._init_cmds = []
diff --git a/sma/__init__.py b/sma/__init__.py
index a70879e32..7b6cd32d6 100755
--- a/sma/__init__.py
+++ b/sma/__init__.py
@@ -36,7 +36,6 @@
# the use or application of the software.
#########################################################################
-import logging
import threading
import time
import socket
@@ -188,7 +187,6 @@ class SMA(SmartPlugin):
def __init__(self, **kwargs):
# TODO: self._own_bt_addr setzen
- self.logger = logging.getLogger(__name__)
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')
diff --git a/sml/__init__.py b/sml/__init__.py
index b1eb80af4..bf08ad475 100755
--- a/sml/__init__.py
+++ b/sml/__init__.py
@@ -20,7 +20,6 @@
# along with SmartHomeNG. If not, see .
#########################################################################
-import logging
import time
import re
import serial
@@ -65,7 +64,6 @@ def __init__(self, **kwargs):
self._dataoffset = 0
self._items = {}
self._lock = threading.Lock()
- self.logger = logging.getLogger(__name__)
if self._device in self._devices:
self._device = self._devices[self._device]
From bc8af66e9699d56b768f93856b659280d69b802a Mon Sep 17 00:00:00 2001
From: Morg42 <43153739+Morg42@users.noreply.github.com>
Date: Sun, 26 Nov 2023 16:56:56 +0100
Subject: [PATCH 6/6] more logging cleanup
---
intercom_2n/__init__.py | 2 --
rcswitch/__init__.py | 2 --
smarttv/__init__.py | 2 --
3 files changed, 6 deletions(-)
diff --git a/intercom_2n/__init__.py b/intercom_2n/__init__.py
index 1c785e053..5956279c8 100755
--- a/intercom_2n/__init__.py
+++ b/intercom_2n/__init__.py
@@ -20,7 +20,6 @@
#########################################################################
import json
-import logging
import os
from time import sleep
import requests
@@ -44,7 +43,6 @@ def __init__(self, **kwargs):
self._password = self.get_parameter_value('password')
self.is_stopped = False
self.sid = None
- self._logger = logging.getLogger(__name__)
self.event_timeout = 30
self.ip_cam = IPCam(self._intercom_ip, ssl=self._ssl, auth_type=self._auth_type, user=self._username, password=self._password)
diff --git a/rcswitch/__init__.py b/rcswitch/__init__.py
index 0198b4321..8446f8303 100755
--- a/rcswitch/__init__.py
+++ b/rcswitch/__init__.py
@@ -19,7 +19,6 @@
# along with SmartHomeNG. If not, see .
#########################################################################
-import logging
from lib.model.smartplugin import SmartPlugin
from socket import gethostname
import time
@@ -36,7 +35,6 @@ class RCswitch(SmartPlugin):
PLUGIN_VERSION = "1.2.2"
def __init__(self, **kwargs):
- self.logger = logging.getLogger(__name__)
self.setupOK = True
self.mapping = {'a': 1, 'A': 1, 'b': 2, 'B': 2, 'c': 3, 'C': 3, 'd': 4, 'D': 4, 'e': 5, 'E': 5}
self.rcswitch_dir = self.get_parameter_value('rcswitch_dir')
diff --git a/smarttv/__init__.py b/smarttv/__init__.py
index bb90f1a44..8b3afd9c9 100755
--- a/smarttv/__init__.py
+++ b/smarttv/__init__.py
@@ -19,7 +19,6 @@
# along with SmartHomeNG. If not, see .
#
-import logging
import socket
import time
import base64
@@ -34,7 +33,6 @@ class SmartTV(SmartPlugin):
PLUGIN_VERSION = "1.3.3"
def __init__(self, **kwargs):
- self.logger = logging.getLogger(__name__)
self._tv_version = self.get_parameter_value('tv_version')
self._host = self.get_parameter_value('host')
self._port = self.get_parameter_value('port')