diff --git a/avdevice/AVDeviceInit.py b/avdevice/AVDeviceInit.py index 869e8fc3d..e75ac24e0 100755 --- a/avdevice/AVDeviceInit.py +++ b/avdevice/AVDeviceInit.py @@ -27,6 +27,7 @@ import codecs import re +import os import threading VERBOSE1 = logging.DEBUG - 1 VERBOSE2 = logging.DEBUG - 2 @@ -305,7 +306,7 @@ def _create_responsecommands(self): else: self._special_commands['Input']['Command'].append(response) self._special_commands['Input']['Ignore'].append(0) - self.logger.log(VERBOSE1, "Initializing {}: Found Input Command and added it to display commands.".format(self._name)) + self.logger.log(VERBOSE2, "Initializing {}: Found Input Command and added it to display commands.".format(self._name)) elif (function == 'title' or function == 'station' or function == 'genre'): if 'Nowplaying' not in self._special_commands: self._special_commands['Nowplaying'] = {'Command': [response]} @@ -340,7 +341,7 @@ def _create_responsecommands(self): self.logger.log(VERBOSE1, "Initializing {}: Adding additional list to function {} for response {} with value {}.".format( self._name, function, response, self._response_commands[response])) except Exception as err: - self.logger.log(VERBOSE1, "Initializing {}: Creating response command for: {}. Message: {}".format(self._name, response, err)) + self.logger.log(VERBOSE2, "Initializing {}: Creating response command for: {}. Message: {}".format(self._name, response, err)) self._response_commands[response] = [[ valuelength, commandlength, position, item, function, 'zone{}'.format(zone), inverse, expectedtype, functiontype]] self._response_commands[response] = sorted(self._response_commands[response], key=lambda x: x[0], reverse=True) @@ -372,8 +373,7 @@ def _read_commandfile(self): try: self.logger.debug("Initializing {}: Starting to read file {}. Lock is {}".format( self._name, self._model, self._threadlock_standard.locked())) - filename = '{}/plugins/avdevice/{}.txt'.format( - self._sh.base_dir, self._model) + filename = '{}/{}.txt'.format(os.path.abspath(os.path.dirname(__file__)), self._model) commands = codecs.open(filename, 'r', 'utf-8') zones = [0] @@ -408,11 +408,13 @@ def _read_commandfile(self): row.append('bool') elif i == 8 and ("increase" in function or "decrease" in function): row.append('int,float') + row[5] = row[5].replace('*', '') else: row.append('') try: row[8] = row[8].replace('string', 'str') row[8] = row[8].replace('num', 'int,float') + row[8] = row[8].replace('|', ',') if row[8] == '': row[8] = 'bool,int,str' except Exception: diff --git a/avdevice/Denon_Items.yaml b/avdevice/Denon_Items.yaml new file mode 100755 index 000000000..38d301606 --- /dev/null +++ b/avdevice/Denon_Items.yaml @@ -0,0 +1,346 @@ +%YAML 1.1 +--- +Denon: + type: foo + + Powerall: + type: bool + visu_acl: rw + avdevice_zone0: power + + Update: + type: bool + visu_acl: rw + avdevice_zone0: statusupdate + enforce_updates: 'yes' + + Power: + type: bool + visu_acl: rw + avdevice_zone1: power + + Mute: + type: bool + visu_acl: rw + avdevice_zone1: mute + + VolumeFL: + type: num + visu_acl: rw + avdevice_zone1: volumefl + cache: 'True' + + VolumeFLUp: + type: bool + visu_acl: rw + avdevice_zone1: volumefl+ + enforce_updates: 'yes' + + VolumeFLDown: + type: bool + visu_acl: rw + avdevice_zone1: volumefl- + enforce_updates: 'yes' + + VolumeFR: + type: num + visu_acl: rw + avdevice_zone1: volumefr + cache: 'True' + + VolumeFRUp: + type: bool + visu_acl: rw + avdevice_zone1: volumefr+ + enforce_updates: 'yes' + + VolumeFRDown: + type: bool + visu_acl: rw + avdevice_zone1: volumefr- + enforce_updates: 'yes' + + Volume: + type: num + visu_acl: rw + avdevice_zone1: volume + cache: 'True' + + VolumeMax: + type: num + visu_acl: ro + avdevice_zone1: volumemax + + VolumeUp: + type: bool + visu_acl: rw + avdevice_zone1: volume+ + enforce_updates: 'yes' + + VolumeDown: + type: bool + visu_acl: rw + avdevice_zone1: volume- + enforce_updates: 'yes' + + VolumeLow: + type: bool + enforce_updates: 'yes' + visu_acl: rw + avdevice_zone1: volumelow + + VolumeHigh: + type: bool + enforce_updates: 'yes' + visu_acl: rw + avdevice_zone1: volumehigh + + Eco: + type: str + visu_acl: rw + avdevice_zone0: eco + + Source: + type: str + visu_acl: rw + avdevice_zone1: input + + Music: + type: bool + visu_acl: ro + eval: 1 if ((sh.Denon.Source() == 'DVD' or sh.Denon.Source() == 'CD' or sh.Denon.Source() == 'NET') and sh.Denon.Power()) else 0 + eval_trigger: + - Denon.Source + - Denon.Power + enforce_updates: 'yes' + + Mode: + type: str + visu_acl: rw + avdevice_zone1: mode + + Dialog: + type: num + visu_acl: rw + avdevice_zone1: dialog + enforce_updates: 'no' + + Dialogtoggle: + type: bool + visu_acl: rw + avdevice_zone1: dialogtoggle + + Subwoofer: + type: num + visu_acl: rw + avdevice_zone1: subwoofer + enforce_updates: 'no' + + Subwoofertoggle: + type: bool + visu_acl: rw + avdevice_zone1: subwoofertoggle + + CinemaEQ: + type: bool + visu_acl: rw + avdevice_zone1: cinemaeq + + Mainspeakers: + type: str + visu_acl: rw + avdevice_zone1: mainspeakers + + Sleep: + type: num + visu_acl: rw + avdevice_zone1: sleep + + Standby: + type: foo + visu_acl: rw + avdevice_zone1: standby + + Bass: + type: num + visu_acl: rw + avdevice_zone1: bass + + BassUp: + type: num + visu_acl: rw + avdevice_zone1: bass+ + enforce_updates: 'yes' + + BassDown: + type: num + visu_acl: rw + avdevice_zone1: bass- + enforce_updates: 'yes' + + Tone: + type: bool + visu_acl: rw + avdevice_zone1: tone + + Trebble: + type: num + visu_acl: rw + avdevice_zone1: trebble + + TrebbleUp: + type: num + visu_acl: rw + avdevice_zone1: trebble+ + enforce_updates: 'yes' + + TrebbleDown: + type: num + visu_acl: rw + avdevice_zone1: trebble- + enforce_updates: 'yes' + + Videoinput: + type: str + visu_acl: rw + avdevice_zone1: videoinput + + Audioinput: + type: str + visu_acl: rw + avdevice_zone1: audioinput + + Videoparams: + type: str + visu_acl: rw + avdevice_zone1: videoparams + + Power2: + type: bool + visu_acl: rw + avdevice_zone2: power + + Source2: + type: str + visu_acl: rw + avdevice_zone2: input + + Music: + type: bool + visu_acl: ro + eval: 1 if ((sh.Denon.Source2() == 'DVD' or sh.Denon.Source2() == 'CD' or sh.Denon.Source2() == 'NET') and sh.Denon.Power2()) else 0 + eval_trigger: + - Denon.Source2 + - Denon.Power2 + + Mute2: + type: bool + visu_acl: rw + avdevice_zone2: mute + + Volume2: + type: num + visu_acl: rw + avdevice_zone2: volume + + Fading: + type: num + + VolumeUp2: + type: bool + visu_acl: rw + avdevice_zone2: volume+ + enforce_updates: 'yes' + + VolumeDown2: + type: bool + visu_acl: rw + avdevice_zone2: volume- + enforce_updates: 'yes' + + VolumeHigh2: + type: bool + visu_acl: rw + avdevice_zone2: volumehigh + enforce_updates: 'yes' + + VolumeLow2: + type: bool + visu_acl: rw + avdevice_zone2: volumelow + enforce_updates: 'yes' + + Sleep2: + type: num + visu_acl: rw + avdevice_zone2: sleep + + Standby2: + type: foo + visu_acl: rw + avdevice_zone2: standby + + Power3: + type: bool + visu_acl: rw + avdevice_zone3: power + + Source3: + type: str + visu_acl: rw + avdevice_zone3: input + + Musik: + type: bool + visu_acl: ro + eval: 1 if ((sh.Denon.Source3() == 'DVD' or sh.Denon.Source3() == 'CD' or sh.Denon.Source3() == 'NET') and sh.Denon.Power3()) else 0 + eval_trigger: + - Denon.Source3 + - Denon.Power3 + + Mute3: + type: bool + visu_acl: rw + avdevice_zone3: mute + + Volume3: + type: num + visu_acl: rw + avdevice_zone3: volume + + Fading: + type: num + + VolumeUp3: + type: bool + visu_acl: rw + avdevice_zone3: volume+ + enforce_updates: 'yes' + + VolumeDown3: + type: bool + visu_acl: rw + avdevice_zone3: volume- + enforce_updates: 'yes' + + VolumeHigh3: + type: bool + visu_acl: rw + avdevice_zone3: volumehigh + enforce_updates: 'yes' + + VolumeLow3: + type: bool + visu_acl: rw + avdevice_zone3: volumelow + enforce_updates: 'yes' + + Sleep3: + type: num + visu_acl: rw + avdevice_zone3: sleep + + Standby3: + type: foo + visu_acl: rw + avdevice_zone3: standby diff --git a/avdevice/Pioneer_Items.yaml b/avdevice/Pioneer_Items.yaml new file mode 100755 index 000000000..df3a7ad88 --- /dev/null +++ b/avdevice/Pioneer_Items.yaml @@ -0,0 +1,218 @@ +%YAML 1.1 +--- + Pioneer: + type: foo + + Update: + type: bool + visu_acl: rw + avdevice_zone0: statusupdate + enforce_updates: 'yes' + + Speakers: + type: num + visu_acl: rw + avdevice_zone1: speakers + + SpeakerA: + type: bool + visu_acl: rw + avdevice_zone1_speakers: 1 + + SpeakerB: + type: bool + visu_acl: rw + avdevice_zone1_speakers: 2 + + Power: + type: bool + visu_acl: rw + avdevice_zone1: power + + Mute: + type: bool + visu_acl: rw + avdevice_zone1: mute + + Volume: + type: num + visu_acl: rw + avdevice_zone1: volume + cache: 'True' + + Fading: + type: num + + VolumeUp: + type: bool + visu_acl: rw + avdevice_zone1: volume+ + enforce_updates: 'yes' + + VolumeDown: + type: bool + visu_acl: rw + avdevice_zone1: volume- + enforce_updates: 'yes' + + VolumeLow: + type: bool + enforce_updates: 'yes' + visu: rw + avdevice_zone1: volumelow + + VolumeHigh: + type: bool + enforce_updates: 'yes' + visu: rw + avdevice_zone1: volumehigh + + Source: + type: num + visu_acl: rw + avdevice_zone1: input + + Music: + type: bool + visu_acl: ro + eval: 1 if (sh.Pioneer.Source() == 13 and sh.Pioneer.Power()) else 0 + eval_trigger: + - Pioneer.Source + - Pioneer.Power + enforce_updates: 'yes' + + Mode: + type: num + visu_acl: rw + avdevice_zone1: mode + + Playingmode: + type: foo + visu_acl: ro + avdevice_zone1: playingmode + + Bass: + type: num + visu_acl: rw + avdevice_zone1: bass + + BassUp: + type: bool + visu_acl: rw + avdevice_zone1: bass+ + enforce_updates: 'yes' + + BassDown: + type: bool + visu_acl: rw + avdevice_zone1: bass- + enforce_updates: 'yes' + + Dialog: + type: num + visu_acl: rw + avdevice_zone1: dialog + + Trebble: + type: num + visu_acl: rw + avdevice_zone1: trebble + + TrebbleUp: + type: bool + visu_acl: rw + avdevice_zone1: trebble+ + enforce_updates: 'yes' + + TrebbleDown: + type: bool + visu_acl: rw + avdevice_zone1: trebble- + enforce_updates: 'yes' + + Tone: + type: bool + visu_acl: rw + avdevice_zone1: tone + + Display: + type: str + visu_acl: ro + avdevice_zone0: display + + HDMI: + type: num + visu_acl: ro + avdevice_zone1: HDMI + + Title: + type: str + visu_acl: ro + avdevice_zone0: title + + Station: + type: str + visu_acl: ro + avdevice_zone0: station + + Genre: + type: str + visu_acl: ro + avdevice_zone0: genre + + Power2: + type: bool + visu_acl: rw + avdevice_zone2: power + + Source2: + type: num + visu_acl: rw + avdevice_zone2: input + + Musik: + type: bool + visu_acl: ro + eval: 1 if (sh.Pioneer.Source2() == 13 and sh.Pioneer.Power2()) else 0 + eval_trigger: + - Musik.Source2 + - Musik.Power2 + enforce_updates: 'no' + + Mute2: + type: bool + visu_acl: rw + avdevice_zone2: mute + + Volume2: + type: num + visu_acl: rw + avdevice_zone2: volume + cache: 'True' + + Fading: + type: num + + VolumeUp2: + type: bool + visu_acl: rw + avdevice_zone2: volume+ + enforce_updates: 'yes' + + VolumeDown2: + type: bool + visu_acl: rw + avdevice_zone2: volume- + enforce_updates: 'yes' + + VolumeHigh2: + type: num + visu_acl: rw + avdevice_zone2: volumehigh + enforce_updates: 'yes' + + VolumeLow2: + type: num + visu_acl: rw + avdevice_zone2: volumelow + enforce_updates: 'yes' diff --git a/avdevice/README.md b/avdevice/README.md index 07a5f475d..a04c5684b 100755 --- a/avdevice/README.md +++ b/avdevice/README.md @@ -29,7 +29,7 @@ avdevice: rs232_port: /dev/ttyUSB1 #rs232_baudrate: 9600 #rs232_timeout: 0.1 - #ignoreresponse: 'RGB,RGC,RGD,GBH,GHH,LM0,VTA,AUA,AUB' + #ignoreresponse: 'RGB,RGC,RGD,GBH,GHH,VTA,AUA,AUB' #forcebuffer: 'GEH01020, GEH04022, GEH05024' #inputignoredisplay: '' #dependson_item: '' @@ -58,20 +58,20 @@ avdevice: * `rs232_port`: If you use a RS232 cable to communicate with your device (highly recommended!) define the interface port * `rs232_baudrate`: baudrate for RS232 * `rs232_timeout`: timeout for RS232 -* `ignoreresponse`: list of values. the plugin doesn't care about responses from the device starting with the given values. List responses for menu navigation, etc. For Pioneer receivers the following list is recommended: RGB, RGC, RGD, GBH, GHH, LM0, VTA, AUA, AUB +* `ignoreresponse`: list of values. the plugin doesn't care about responses from the device starting with the given values. List responses for menu navigation, etc. For Pioneer receivers the following list is recommended: RGB, RGC, RGD, GBH, GHH, VTA, AUA, AUB * `forcedbuffer`: list of strings. If for whatever reason you don't want to buffer the response from your device you can still define specific responses that should get buffered. This is important for responses that change or get sent very quickly. Artist, title, radio station, etc. are examples that should be put here. For Pioneer receivers the following list is recommended: GEH01020, GEH04022, GEH05024 * `inputignoredisplay`: list of int. The value of the LCD display on your receiver might get updated very often, e.g. when it shows song titles as a scrolling text. To avoid constant display updates and therefore possible confusion with relevant answers of your device listing source inputs like internet radio, LAN streaming, etc. here is highly recommended. For Pioneer receivers the following list is recommended: 26,38,40,41,44,17,02,48,0 * `dependson_item`: item. If given item has given value the commands are sent to the device, otherwise they are not. Relevant if you have your device connected to a power socket that can be turned off. * `dependson_value`: boolean. If given item has given value the commands are sent to the device, otherwise they are not. Relevant if you have your device connected to a power socket that can be turned off. -* `errorresponse`: list of strings. The standard error responses from your device. For Pioneer receivers they are "E" followed by a number. If no values are provided error answers from your device might get recognized much slower but actually should still get recognized. +* `errorresponse`: list of strings. The standard error responses from your device. For Pioneer receivers they are "E" followed by a number. If no values are provided error answers from your device might get recognized much slower but actually should still get recognized. * `resetonerror`: boolean. Reset the value of the item that could not be updated. E.g. you set the volume of zone 2 to "100". If either the dependson item is off or the device sends an error response or after several connection and send retries the expected response is not received, the volume item gets set to value it had before you sent the command. That way you avoid having a wrong value displayed in your Visu. * `depend0_power0`: boolean. If the dependson item is off the power off all zones are set to off. This is especially relevant for a correct representation in your Visu when you have a powered on device but turn off the power socket. * `depend0_volume0`: boolean. Same as above but in this case the volume is set to 0 for all zones. This is for Visu purposes only. * `sendretries`: integer. This value defines how often a command should be sent when receiving a wrong answer from the device. * `resendwait`: float. Seconds the plugin should wait between each resend retry. -* `reconnectretries`: integer. If the plugin can not connect to the device it retries this often. This is especially useful for TCP connections on devices that are plugged into a switchable socket as most receivers need about 40-50 seconds to boot their network device. -* `secondstokeep`: integer. Seconds the plugin should temporarily save a command to retry later on after establishing a connection. This is especially useful for TCP connections on devices that are plugged into a switchable socket as most receivers need about 40-50 seconds to boot their network device. -* `responsebuffer`: integer or boolean. Set this to a number to collect quickly received responses in a buffer and evaluate them collectively. The standard value should be fine and prevent responses getting lost. Some receivers might first respond to a command with an update of the display and then with the actual value. The buffer ensures the correct evaluation of the response. +* `reconnectretries`: integer. If the plugin can not connect to the device it retries this often. This is especially useful for TCP connections on devices that are plugged into a switchable socket as most receivers need about 40-50 seconds to boot their network device. +* `secondstokeep`: integer. Seconds the plugin should temporarily save a command to retry later on after establishing a connection. This is especially useful for TCP connections on devices that are plugged into a switchable socket as most receivers need about 40-50 seconds to boot their network device. +* `responsebuffer`: integer or boolean. Set this to a number to collect quickly received responses in a buffer and evaluate them collectively. The standard value should be fine and prevent responses getting lost. Some receivers might first respond to a command with an update of the display and then with the actual value. The buffer ensures the correct evaluation of the response. * `autoreconnect`: boolean. Automatically tries to reconnect if no response is received or connection is lost. This should not be necessary as the plugin always tries to reconnect before sending a command. ### items.yaml @@ -80,7 +80,12 @@ avdevice: specifiy the zone number and instance. The command has to correspond to a "base" command in the relevant text configuration file in the avdevice plugin folder named the same as the "model" configured in plugin.yaml. -Only use the first part of the command before the space, e.g. "power" instead of "power on" or "power off". "volume" instead of "volume set", etc. +It is important to set the correct type for each item. The Pioneer RS232 codeset expects bool and int types only. +For example to set the listening mode to "pure direct", the item has to be int and you set it to the value "8". + +Full item examples are included as separate yaml files for Pioneer and Denon devices. In general the items are setup the same independent of the AV device model. The examples include the tested items/commands and allow easy copy/paste. + +Speakers Items are special and should be set up the way mentioned in the following example. 1 and 2 correspond to the value the speaker command expects. #### Example @@ -89,19 +94,6 @@ Only use the first part of the command before the space, e.g. "power" instead of Pioneer: type: foo - Update: - type: bool - visu_acl: rw - avdevice_zone0@pioneer_one: statusupdate - enforce_updates: 'yes' - knx_dpt: 1 - - Running: - type: bool - visu_acl: ro - enforce_updates: 'yes' - value: 0 - Power: type: bool visu_acl: rw @@ -109,61 +101,21 @@ Pioneer: enforce_updates: 'no' knx_dpt: 1 - Mute: - type: bool - visu_acl: rw - avdevice_zone1@pioneer_one: mute - enforce_updates: 'no' - knx_dpt: 1 - - Volume: + Speakers: type: num visu_acl: rw - enforce_updates: 'no' - avdevice_zone1@pioneer_one: volume - - VolumeUp: - type: bool - visu_acl: rw - avdevice_zone1@pioneer_one: volume+ - enforce_updates: 'yes' + avdevice_zone1: speakers - VolumeDown: + SpeakerA: type: bool visu_acl: rw - avdevice_zone1@pioneer_one: volume- - enforce_updates: 'yes' + avdevice_zone1_speakers: 1 - VolumeLow: + SpeakerB: type: bool - enforce_updates: 'yes' - avdevice_zone1@pioneer_one: volumelow visu_acl: rw + avdevice_zone1_speakers: 2 - VolumeHigh: - type: bool - enforce_updates: 'yes' - visu_acl: rw - avdevice_zone1@pioneer_one: volumehigh - - Source: - type: num - visu_acl: rw - knx_dpt: 7 - avdevice_zone1@pioneer_one: input - enforce_updates: 'no' - - Power2: - type: bool - visu_acl: rw - avdevice_zone2@pioneer_one: power - enforce_updates: 'no' - - Source2: - type: num - visu_acl: rw - avdevice_zone2@pioneer_one: input - enforce_updates: 'no' ``` ### model.txt @@ -176,9 +128,9 @@ Each line holds one specific command that should be sent to the device. You also * `zone`: Number of zone. Has to correspond to the attribute in item.yaml. E.g. for zone 1 use "avdevice_zone1: command". Zone 0 holds special commands like navigating in the menu, display reponse, information about currently playing songs, etc. -* `function`: name of the function. You can name them whatever you like. You reference this value in the item using avdevice_zoneX: function. +* `function`: name of the function. You can name it whatever you like. You reference this value in the item using avdevice_zoneX: function. -* `functiontype`: for boolean functions use "on" or "off". For commands setting a specific value like source, input mode, volume, etc. use "set". To increase ot decrease a value use the corresponding "increase" or "decrease". For everything else leave empty! +* `functiontype`: for boolean functions use "on" or "off". For commands setting a specific value like source, input mode, volume, etc. use "set". To increase or decrease a value use the corresponding "increase" or "decrease". For everything else leave empty! * `send`: the command to be sent, e.g. power off is "PF" for Pioneer receivers. You can use a pipe "|" if more than one command should be sent. That might be necessary for power on commands via RS232, e.g. for Pioneer receivers to power on "PO|PO" forces the plugin to send the "PO" command twice. Use stars "\*" to specify the format of the value to be sent. Let's say your device expects the value for volume as 3 digits, a "\*\*\*VL" ensures that even setting the volume to "5" sends the command as "005VL" @@ -190,9 +142,9 @@ Each line holds one specific command that should be sent to the device. You also * `invertresponse`: some devices are stupid enough to reply with a "0" for "on" and "1" for "off". E.g. a Pioneer receiver responds with "PWR0" if the device is turned on. Configure with "yes" if your device is quite stupid, too. -* `maxvalue`: You can define the maximum value for setting a specific function. This might be most relevant for setting the volume. If you configure this with "100" and set the volume to "240" (via Visu or CLI) the value will get clamped by the plugin and set to "100". +* `maxvalue`: You can define the maximum value for setting a specific function. This might be most relevant for setting the volume. If you configure this with "100" and set the volume to "240" (via Visu or CLI) the value will get clamped by the plugin and set to "100". -* `responsetype`: Defines the type of the response value and can be set to "bool", "num" or "string" or a mixture of them. Most response types are set automatically on startup but you can force specific type using this value. It is recommended to use the values suggested in the txt files that come with the plugin. +* `responsetype`: Defines the type of the response value and can be set to "bool", "num" or "str" or a mixture of them (separated by a pipe "|"). Most response types are set automatically on startup but you can force a specific type using this value. It is recommended to use the values suggested in the txt files that come with the plugin. #### Example @@ -201,31 +153,27 @@ Each line holds one specific command that should be sent to the device. You also ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; MAXVALUE; RESPONSETYPE 1; power; on; PO|PO; ?P; PWR*; RW; yes 1; power; off; PF; ?P; PWR*; RW; yes -1; volume+; VU; ; VOL; W -1; volume-; VD; ; VOL; W -1; volumehigh; 150VL; ?V; VOL150; W -1; volumelow; 110VL; ?V; VOL110; W +1; volume+; increase; VU; ; VOL; W +1; volume-; decrease; VD; ; VOL; W 1; volume; set; ***VL; ?V; VOL***; RW; ; 185 -1; mute; on; MO; ?M; MUT*; RW; yes -1; mute; off; MF; ?M; MUT*; RW; yes 1; input; set; **FN; ?F; FN**; RW +1; speakers; set; *SPK; ?SPK; SPK*; RW 2; power; on; APO|APO; ?AP; APR*; RW; yes 2; power; off; APF; ?AP; APR*; RW; yes -2; volume+; ZU; ; ZV; W -2; volume-; ZD; ; ZV; W -2; volumehigh; 75ZV; ?ZV; ZV75; W -2; volumelow; 45ZV; ?ZV; ZV45; W -2; volume; set; **ZV; ?ZV; ZV**; RW; ; 81 -2; mute; on; Z2MO; ?Z2M; Z2MUT*; RW; yes -2; mute; off; Z2MF; ?Z2M; Z2MUT*; RW; yes -2; input; set; **ZS; ?ZS; Z2F**; RW -0; title; ; ; GEH01020; R -0; station; ; ; GEH04022; R -0; genre; ; ; GEH05024; R -0; display; ?FL; ?FL; FL******************************; R -1; speakers; set; *SPK; ?SPK; SPK*; RW +0; title; ; ; ; GEH01020; R +0; station; ; ; ; GEH04022; R +0; genre; ; ; ; GEH05024; R +0; display; ; ?FL; ?FL; FL******************************; R + ``` -### Debugging +### Troubleshooting +1.) Have a look at the smarthome logfile. If you can't figure out the reason for your problem, change the verbose level in logging.yaml. +You can use level 10 (=DEBUG), 9 (VERBOSE1) and 8 (VERBOSE2) as debugging levels. + +2.) Concerning send and response entries in the textfile, make sure the number of stars correspond to the way your device wants to receive the command or sends the response. +Example 1: Your Pioneer receiver expects the value for the volume as three digits. So the command needs three stars. If you now set the item to a value with only two digits, like 90, the plugin converts the command automatically to have a leading 0. +Example 2: Your Denon receiver responds with values like ON, OFF or STANDBY to power commands. Replace every character with a star! ON = 2 stars, OFF = 3 stars, etc. +Example 3: Sending or receiving strings of different length like "CD", "GAME", etc. should be set up with one star only. Set the responsetype accordingly! -You can use level 9 (VERBOSE1) and 8 (VERBOSE2) as debugging levels in logging.yaml +3.) Set the response type in the textfile to the correct value. The plugin tries to anticipate the correct value but that doesn't always work. The sleep timer of Denon devices is a wonderfully sick example: You can set values betwwen 1 and 120 to set the timer in minutes. If you want to turn it off, the receiver expects the value "OFF" instead of a zero. The plugin fixes that problem if you set the responsetype to bool|num. As soon as you set the item to 0, it magically converts that value to "OFF" and the other way around when receiving "OFF". diff --git a/avdevice/__init__.py b/avdevice/__init__.py index 34842cd8e..6baee7ffd 100644 --- a/avdevice/__init__.py +++ b/avdevice/__init__.py @@ -26,12 +26,9 @@ import logging from lib.model.smartplugin import SmartPlugin from itertools import groupby -import threading -import os import io import time import re -import codecs import errno import serial import socket @@ -47,9 +44,9 @@ class AVDevice(SmartPlugin): ALLOW_MULTIINSTANCE = True PLUGIN_VERSION = "1.3.2" - def __init__(self, smarthome, + def __init__(self, smarthome, model='', - ignoreresponse='RGB,RGC,RGD,GBH,GHH,LM0,VTA,AUA,AUB', + ignoreresponse='RGB,RGC,RGD,GBH,GHH,VTA,AUA,AUB', errorresponse='E02,E04,E06', forcebuffer='GEH01020, GEH04022, GEH05024', inputignoredisplay='', @@ -97,7 +94,7 @@ def __init__(self, smarthome, self._parsinginput = [] try: - self._model = self.get_parameter_value('model') + self._model = self.get_parameter_value('model') self._resend_wait = float(self.get_parameter_value('resendwait')) self._secondstokeep = int(self.get_parameter_value('secondstokeep')) self._auto_reconnect = self.get_parameter_value('autoreconnect') @@ -160,7 +157,7 @@ def _resetitem(self): self.logger.log(VERBOSE1, "Resetting {}: Cannot find Sendingcommand. Using first Command in queue: {}. Message: {}".format(self._name, response, e)) sorted_response_commands = sorted(self._response_commands, key=len, reverse=True) for key in sorted_response_commands: - self.logger.log(VERBOSE1, "Resetting {}: Trying to reset Item. Comparing: {} with {}".format(self._name, key, response)) + self.logger.log(VERBOSE2, "Resetting {}: Trying to reset Item. Comparing: {} with {}".format(self._name, key, response)) for resp in response: for entry in self._response_commands[key]: try: @@ -309,12 +306,12 @@ def _write_itemsdict(self, data): sorted_response_commands = sorted(self._response_commands, key=len, reverse=True) updated = 0 for command in sorted_response_commands: - self.logger.log(VERBOSE1, "Storing Values {}: Comparing command {}.".format(self._name, command)) + self.logger.log(VERBOSE2, "Storing Values {}: Comparing command {}.".format(self._name, command)) if data == command: self.logger.debug("Storing Values {}: Response is identical to expected response. Skipping Storing: {}".format(self._name, data)) break for entry in self._response_commands[command]: - self.logger.log(VERBOSE1, "Storing Values {}: Comparing entry {}.".format(self._name, entry)) + self.logger.log(VERBOSE2, "Storing Values {}: Comparing entry {}.".format(self._name, entry)) if entry[1] == entry[2]: commandstart = 0 commandend = entry[2] @@ -337,7 +334,7 @@ def _write_itemsdict(self, data): self._items[zone][function]['Value'] = receivedvalue self.logger.debug("Storing Values {}: Found writeable dict key: {}. Zone: {}. Value {} with type {}. Function: {}.".format(self._name, command, zone, receivedvalue, expectedtype, function)) updated = 1 - return self._items[zone][function], receivedvalue, expectedtype + return self._items[zone][function], receivedvalue, expectedtype break else: self.logger.debug("Storing Values {}: Found writeable dict key: {} with type {}, but received value {} is type {}. Not writing value!".format(self._name, command, expectedtype, receivedvalue, type(receivedvalue))) @@ -357,7 +354,7 @@ def _write_itemsdict(self, data): if updated == 1: return self._items[zone][function], receivedvalue, expectedtype else: - return 'empty', 'empty', 'empty' + return 'empty', 'empty', 'empty' # Finding relevant items for the plugin based on the avdevice keyword def parse_item(self, item): @@ -557,7 +554,7 @@ def _processing_response(self, socket): break self._send_commands.pop(0) self._sendingcommand = 'done' - self.logger.debug("Processing Response {}: Response {} is same as expected {}. Removing command from send list. It is now: {}. Ignore responses are: {}".format( + self.logger.debug("Processing Response {}: Response {} is same as expected {} and defined as response to be ignored. Removing command from send list. It is now: {}. Ignore responses are: {}".format( self._name, line, compare, self._send_commands, self._ignore_response)) sending = self._send('command', 'commandremoval') except Exception as err: @@ -644,7 +641,7 @@ def run(self): self._items = self.init._addstatusupdate() self._response_commands, self._special_commands = self.init._create_responsecommands() self._power_commands = self.init._create_powercommands() - self._query_commands, self._query_zonecommands = self.init._create_querycommands() + self._query_commands, self._query_zonecommands = self.init._create_querycommands() self.logger.log(VERBOSE1, "Initializing {}: Functions: {}, Number of Zones: {}".format(self._name, self._functions, self._number_of_zones)) self.logger.log(VERBOSE1, "Initializing {}: Responsecommands: {}.".format(self._name, self._response_commands)) self.logger.log(VERBOSE1, "Initializing {}: Special Commands: {}".format(self._name, self._special_commands)) @@ -991,7 +988,7 @@ def _duplicateindex(seq,item): expectedindices = _duplicateindex(expectedresponse, expected) for expectedindex in expectedindices: - if self._send_commands[expectedindex] not in updatedcommands: + if self._send_commands[expectedindex] not in updatedcommands: expectedtype = self._send_commands[expectedindex].split(',') try: expectedtype[3:] = [','.join(expectedtype[3:])] @@ -1000,9 +997,11 @@ def _duplicateindex(seq,item): testvalue = '' if not valuetype == testvalue: updatedcommands.append(self._send_commands[expectedindex]) - self.logger.log(VERBOSE2, "Parsing Input {}: Test Value is not same as Valuetype: {}. Adding to Sendcommands again.".format(self._name, testvalue, valuetype)) + self.logger.log(VERBOSE2, "Parsing Input {}: Test Value {} of {} is not same as Valuetype: {}. Adding to Sendcommands again.".format( + self._name, testvalue, self._send_commands[expectedindex], valuetype)) else: - self.logger.log(VERBOSE2, "Parsing Input {}: Test Value is same as Valuetype: {}. Not adding to Sendcommands again.".format(self._name, testvalue, valuetype)) + self.logger.log(VERBOSE1, "Parsing Input {}: Test Value {} of {} is same as Valuetype: {}. Not adding to Sendcommands again.".format( + self._name, testvalue, self._send_commands[expectedindex], valuetype)) except Exception as err: self.logger.log(VERBOSE1, "Parsing Input {}: Write to dict problems: {}".format(self._name, err)) @@ -1075,7 +1074,7 @@ def _duplicateindex(seq,item): if not data == 'ERROR' and data not in self._error_response: self.logger.log(VERBOSE1, "Parsing Input {}: Starting to compare values for data {}.".format(self._name, data)) for key in sorted_response_commands: - self.logger.log(VERBOSE1, "Parsing Input {}: Starting to compare values for data {} with key: {}.".format(self._name, data, key)) + self.logger.log(VERBOSE2, "Parsing Input {}: Starting to compare values for data {} with key: {}.".format(self._name, data, key)) if data == key: tempcommands = [] for entry in self._send_commands: @@ -1180,19 +1179,19 @@ def _duplicateindex(seq,item): value = receivedvalue self.logger.debug("Parsing Input {}: Found key {} in response at position {} with value {}.".format( self._name, key, index, value)) - + for entry in self._keep_commands: self.logger.log(VERBOSE1, "Parsing Input {}: Testing Keep Command entry {}".format( self._name, entry, self._keep_commands.get(entry))) if data in self._keep_commands.get(entry).split(",")[2].split("|"): self.logger.debug("Parsing Input {}: Removing {} from Keep Commands {} because corresponding value received.".format( self._name, entry, self._keep_commands.get(entry), self._keep_commands)) - self._keep_commands.pop(entry) - break + self._keep_commands.pop(entry) + break if function in self._items[zone].keys(): self._items[zone][function]['Value'] = value self.logger.log(VERBOSE1, "Parsing Input {}: Updated Item dict {}".format(self._name, self._items[zone][function])) - + for singleitem in item: singleitem(value, 'AVDevice', self._tcp) self.logger.debug("Parsing Input {}: Updating Item {} with {} Value: {}.".format( @@ -1227,7 +1226,7 @@ def _duplicateindex(seq,item): if self._send_commands == []: self._sendingcommand = 'done' self.logger.log(VERBOSE1, "Parsing Input {}: Finished. Send Commands: {}, sending Command: {}. Data: {}".format( - self._name, self._send_commands, self._sendingcommand, data)) + self._name, self._send_commands, self._sendingcommand, data)) except Exception as err: self.logger.error("Parsing Input {}: Problems parsing input. Error: {}".format(self._name, err)) finally: @@ -1610,8 +1609,10 @@ def update_item(self, item, caller=None, source=None, dest=None): value = value.upper() self.logger.debug("Updating Item for avdevice_{}: Value has to be string. Value is {}".format(self._name.lower(), value)) try: - command_re = commandinfo[2].replace('*', '{}'.format(value)) - response = commandinfo[4].replace('*', '{}'.format(value)) + command_re = commandinfo[2].replace('*', '{}'.format(value), 1) + command_re = command_re.replace('*', '') + response = commandinfo[4].replace('*', '{}'.format(value), 1) + response = response.replace('*', '') except Exception: command_re = commandinfo[2] response = commandinfo[4] diff --git a/avdevice/denon-avr6300.txt b/avdevice/denon-avr6300.txt index 1676ba907..9db8423e4 100644 --- a/avdevice/denon-avr6300.txt +++ b/avdevice/denon-avr6300.txt @@ -1,13 +1,13 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; MAXVALUE; RESPONSETYPE 0; power; on; PWON|PWON; PW?; PW**; RW 0; power; off; PWSTANDBY; PW?; PW*******; RW -0; eco; set; ECO*; ECO?; ECO*; RW; ; ; string,bool +0; eco; set; ECO*; ECO?; ECO*; RW; ; ; str|bool 1; power; on; ZMON; ZM?; ZM**; RW 1; power; off; ZMOFF; ZM?; ZM***; RW 1; mute; on; MUON; MU?; MU**; RW 1; mute; off; MUOFF; MU?; MU***; RW -1; sleep; set; SLP***; SLP?; SLP***; RW; ; 120; num,bool -1; standby; set; STBY*; STBY?; STBY*; RW; ; ; string +1; sleep; set; SLP***; SLP?; SLP***; RW; ; 120; num|bool +1; standby; set; STBY*; STBY?; STBY*; RW; ; ; str 1; volume; set; MV**; MV?; MV**; RW; ; 90 1; volume+; increase; MVUP; ; MV; W 1; volume-; decrease; MVDOWN; ; MV; W @@ -20,15 +20,31 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; 1; volumelow; ; MV50; MV?; MV50; W; ; ; num 1; volumehigh; ; MV75; MV?; MV75; W; ; ; num 1; volumemax; ; MVMAX **; MV?; MVMAX **; RW -1; input; set; SI*; SI?; SI*; RW; ; ; string -1; mode; set; MS*; MS?; MS*; RW; ; ; string -1; audioinput; set; SD*; SD?; SD*; RW; ; ; string,bool -1; videoinput; set; SV*; SV?; SV*; RW; ; ; string,bool -1; digitalinput; set; DC*; DC?; DC*; RW; ; ; string -1; video; set; VS*; ; VS*; RW; ; ; string +1; input; set; SI*; SI?; SI*; RW; ; ; str +1; mode; set; MS*; MS?; MS*; RW; ; ; str +1; audioinput; set; SD*; SD?; SD*; RW; ; ; str +1; videoinput; set; SV*; SV?; SV*; RW; ; ; str|bool +1; videoparams; set; VS*; ; VS*; RW; ; ; str +1; tone; on; PSTONE CTRL ON; PSTONE CTRL ?; PSTONE CTRL **; RW +1; tone; off; PSTONE CTRL OFF; PSTONE CTRL ?; PSTONE CTRL ***; RW +1; bass; set; PSBAS **; PSBAS ?; PSBAS **; RW; ; 99 +1; trebble; set; PSTRE **; PSTRE ?; PSTRE **; RW; ; 99 +1; bass+; increase; PSBAS UP; ; PSBAS; W +1; bass-; decrease; PSBAS DOWN; ; PSBAS; W +1; trebble+; increase; PSTRE UP; ; PSTRE; W +1; trebble-; decrease; PSTRE DOWN; ; PSTRE; W +1; dialogtoggle; on; PSDIL ON; PSDIL ?; PSDIL **; RW +1; dialogtoggle; off; PSDIL OFF; PSDIL ?; PSDIL ***; RW +1; dialog; set; PSDIL **; PSDIL ?; PSDIL **; RW; ; 62 +1; subwoofertoggle; on; PSSWL ON; PSSWL ?; PSSWL **; RW +1; subwoofertoggle; off; PSSWL OFF; PSSWL ?; PSSWL ***; RW +1; subwoofer; set; PSSWL **; PSSWL ?; PSSWL **; RW; ; 62 +1; cinemaeq; on; PSCINEMA EQ.ON; PSCINEMA EQ. ?; PSCINEMA EQ.**; RW +1; cinemaeq; off; PSCINEMA EQ.OFF; PSCINEMA EQ. ?; PSCINEMA EQ.***; RW +1; mainspeakers; set; PSSP:*; PSSP: ?; PSSP:*; RW; ; ; str 2; power; on; Z2ON; Z2?; Z2**; RW 2; power; off; Z2OFF; Z2?; Z2***; RW -2; input; set; Z2*; Z2?; Z2*; RW; ; ; string +2; input; set; Z2*; Z2?; Z2*; RW; ; ; str 2; mute; on; Z2MUON; Z2MU?; Z2MU**; RW 2; mute; off; Z2MUOFF; Z2MU?; Z2MU***; RW 2; volume+; increase; Z2UP; ; Z2; W @@ -36,11 +52,11 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; 2; volumelow; ; Z250; MV?; Z250; W; ; ; num 2; volumehigh; ; Z275; MV?; Z275; W; ; ; num 2; volume; set; Z2**; Z2?; Z2**; RW; ; 90 -2; standby; set; Z2STBY*; Z2STBY?; Z2STBY*; RW; ; ; string -2; sleep; set; Z2SLP***; Z2SLP?; Z2SLP***; RW; ; 120; num,bool +2; standby; set; Z2STBY*; Z2STBY?; Z2STBY*; RW; ; ; str +2; sleep; set; Z2SLP***; Z2SLP?; Z2SLP***; RW; ; 120; num|bool 3; power; on; Z3ON; Z3?; Z3**; RW 3; power; off; Z3OFF; Z3?; Z3***; RW -3; input; set; Z3*; Z3?; Z3*; RW; ; ; string +3; input; set; Z3*; Z3?; Z3*; RW; ; ; str 3; mute; on; Z3MUON; Z3MU?; Z3MU**; RW 3; mute; off; Z3MUOFF; Z3MU?; Z3MU***; RW 3; volume+; increase; Z3UP; ; Z3; W @@ -48,5 +64,5 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; 3; volumelow; ; Z350; MV?; Z350; W; ; ; num 3; volumehigh; ; Z375; MV?; Z375; W; ; ; num 3; volume; set; Z3**; Z3?; Z3**; RW; ; 90 -3; standby; set; Z3STBY*; Z3STBY?; Z3STBY*; RW; ; ; string -3; sleep; set; Z3SLP***; Z3SLP?; Z3SLP***; RW; ; 120; num,bool \ No newline at end of file +3; standby; set; Z3STBY*; Z3STBY?; Z3STBY*; RW; ; ; str +3; sleep; set; Z3SLP***; Z3SLP?; Z3SLP***; RW; ; 120; num|bool diff --git a/avdevice/plugin.yaml b/avdevice/plugin.yaml index ed20e3bc3..ed90e48df 100755 --- a/avdevice/plugin.yaml +++ b/avdevice/plugin.yaml @@ -19,7 +19,7 @@ plugin: parameters: # Definition of parameters to be configured in etc/plugin.yaml - model: + model: type: str default: '' mandatory: True @@ -27,51 +27,51 @@ parameters: de: 'Name des Geräts. Muss mit dem Namen der Textdatei unter plugins/avdevice korrelieren, die sämtliche Befehle beinhaltet.' en: 'Name of AV device. Has to correspond to a text file with the same name in the folder plugins/avdevice including all commands.' - tcp_ip: + tcp_ip: type: ip default: 0.0.0.0 description: de: 'Beim Nutzen der TCP Verbindungen ist die IP Adresse des Endgeräts anzugeben.' en: 'If you use TCP connection define IP address of your device.' - tcp_port: + tcp_port: type: int default: 23 description: de: 'Beim Nutzen der TCP Verbindungen ist der Port anzugeben, auf dem das Gerät Verbindungen zulässt. Für Denon: 23, für Pioneer: 8002.' en: 'If you use TCP connection define the port where your device accepts TCPIP connections. For Denon use 23, for Pioneer 8002.' - tcp_timeout: + tcp_timeout: type: int default: 1 description: de: 'Beim Nutzen der TCP Verbindungen kann ein Timeout angegeben werden.' en: 'If you use TCP connection you can define a connection timeout.' - rs232_port: + rs232_port: type: str default: '' description: de: "Beim Nutzen einer RS232 Schnittstelle (empfohlen!) ist die serielle Schnittstelle anzugeben." en: "If you use a RS232 cable to communicate with your device (highly recommended!) define the serial port." - rs232_baudrate: + rs232_baudrate: type: int default: 9600 description: de: "Beim Nutzen einer RS232 Schnittstelle ist die benötigte Baudrate anzugeben." en: "If you use a RS232 interface define the baudrate." - rs232_timeout: + rs232_timeout: type: float default: 0.1 description: de: "Beim Nutzen einer RS232 Schnittstelle kann ein Timeout zum Lesen und Schreiben definiert werden." en: "If you use a RS232 interface you can define read and write timeout." - ignoreresponse: + ignoreresponse: type: str - default: 'RGB,RGC,RGD,GBH,GHH,LM0,VTA,AUA,AUB' + default: 'RGB,RGC,RGD,GBH,GHH,VTA,AUA,AUB' description: de: "Das Plugin ignoriert Antworten die mit den hier angegebenen Werten starten, beispielsweise Rückmeldungen für die Menünavigation, etc. Der Defaultwert ist für Pioneer Receiver empfohlen." en: "The plugin doesn't care about responses from the device starting with the given values. List responses for menu navigation, etc. The default value is recommended for Pioneer receivers." @@ -82,8 +82,8 @@ parameters: description: de: "Wenn aus irgendeinem Grund die Antworten nicht gepuffert werden sollen, können hier dennoch Antworten definiert werden, die sehr wohl gepuffert werden. Dies ist besonders wichtig bei Informationen, die schnell hintereinander gesendet werden bzw. wechseln wie Künstler, Musiktitel, Radiostation, etc. Der Defaultwert ist für Pioneer Receiver empfohlen." en: "If for whatever reason you don't want to buffer the response from your device you can still define specific responses that should get buffered. This is important for responses that change or get sent very quickly. Artist, title, radio station, etc. are examples that should be put here. The default value is recommended for Pioneer receivers." - - inputignoredisplay: + + inputignoredisplay: type: str default: '' description: @@ -103,81 +103,80 @@ parameters: description: de: "Wenn das angegebene Item den angegebenen Wert erhält, werden die Befehle gesendet, ansonsten nicht. Das ist insbesondere dann sinnvoll, wenn das Gerät an einer schaltbaren Steckdose hängt." en: " If given item has given value the commands are sent to the device, otherwise they are not. Relevant if you have your device connected to a power socket that can be turned off." - - errorresponse: + + errorresponse: type: str default: 'E02,E04,E06' description: de: "Standard Fehlermeldungen des Geräts, bei Pioneer beispielsweise ein 'E' gefolgt von einer Nummer. Werden diese Antworten hier nicht angegeben, werden Rückmeldungen unter Umständen deutlich langsamer verarbeitet, aber voraussichtlich trotzdem erkannt." en: "The standard error responses from your device. For Pioneer receivers they are 'E' followed by a number. If no values are provided error answers from your device might get recognized much slower but actually should still get recognized." - + resetonerror: type: bool default: False description: de: "Zurücksetzen des Items auf den vorigen Wert, wenn kein Update durchgeführt werden konnte, zB das Setzen der Lautstärke in einer abgeschalteten Zone. Sobald das dependson Item ausgeschaltet wird oder mehrere Verbindungs- und Sendeversuche fehlgeschlagen sind, wird das Item zurückgesetzt, damit keine falschen Werte in der Visu angezeigt werden." en: "Reset the value of the item that could not be updated. E.g. you set the volume of zone 2 when it is not powered on. If either the dependson item is off or the device sends an error response or after several connection and send retries the expected response is not received, the item gets set to the value it had before you sent the command. That way you avoid having a wrong value displayed in your Visu." - - depend0_power0: + + depend0_power0: type: bool default: False description: de: "Wenn das dependson Item abgeschaltet ist, werden alle Poweritems ebenfalls auf 0 gesetzt. Das ist dann relevant, wenn beispielsweise das Gerät eingeschaltet ist, die Steckdose aber ausgeschaltet wird. Durch Aktivieren dieser Funktion werden automatisch die Poweritems auf 0 gesetzt." en: "If the dependson item is off the power off all zones are set to off. This is especially relevant for a correct representation in your Visu when you have a powered on device but turn off the power socket." - - depend0_volume0: + + depend0_volume0: type: bool default: False description: de: "Wie beim obigen Attribut dient auch diese Funktion zum korrekten Update der Visu auf den Lautstärkewert 0, sobald das dependson Item deaktiviert wird (zB Ausschalten der Steckdose)." en: "Same as above but in this case the volume is set to 0 for all zones. This is for Visu purposes only." - - sendretries: + + sendretries: type: int default: 10 description: de: "Dieser Wert definiert, wie oft bei einer falschen Antwort versucht werden soll, den Befehl nochmals zu senden." en: "This value defines how often a command should be sent when receiving a wrong answer from the device." - + resendwait: type: float default: 1.0 description: de: "Angabe der Pause zwischen Resend Versuchen in Sekunden" en: "Seconds the plugin should wait between each resend retry." - - reconnectretries: + + reconnectretries: type: int default: 13 description: de: "Anzahl der Verbindungsversuche bei Verbindungsproblemen. Das ist insbesondere bei TCP Verbindungen von Geräten relevant, die an schaltbaren Steckdosen hängen, da diese oftmals 30-40 Sekunden zum Hochfahren benötigen." en: "If the plugin can not connect to the device it retries this often. This is especially useful for TCP connections on devices that are plugged into a switchable socket as most receivers need about 40-50 seconds to boot their network device." - - secondstokeep: + + secondstokeep: type: int default: 50 description: de: "Dauer in Sekunden, wie lange ein Kommando, das nicht erfolgreich war in einem Zwischenspeicher aufbewahrt werden soll. Dies ist besonders bei TCP Verbindungen mit Geräten an schaltbaren Steckdosen relevant, da diese ofmals 30-40 Sekunden zum Hochfahren benötigen." en: "Seconds the plugin should temporarily save a command to retry later on after establishing a connection. This is especially useful for TCP connections on devices that are plugged into a switchable socket as most receivers need about 40-50 seconds to boot their network device." - + responsebuffer: type: int default: 5 description: de: "Schnell hintereinander empfangene Werte werden bei einer negativen Attributangabe im Puffer gespeichert und gemeinsam verarbeitet. Der Standardwert sollte dafür sorgen, dass keine Antworten verloren gehen. Einige Receiver antworten unter Umständen immer zuerst mit der Angabe zum auf dem Display gezeigten Wert. Der Puffer sorgt dafür, dass auch eine nachfolgende Rückmeldung evaluiert wird." en: "Set this to a number to collect quickly received responses in a buffer and evaluate them collectively. The standard value should be fine and prevent responses getting lost. Some receivers might first respond to a command with an update of the display and then with the actual value. The buffer ensures the correct evaluation of the response." - - autoreconnect: + + autoreconnect: type: bool default: False description: de: "Automatischer Versuch, sich mit dem Gerät zu verbinden, wenn keine Rückmeldung kommt oder die Verbindung verloren wurde. Dies sollte nicht notwendig sein, da das Plugin ohnehin bei jedem neuen Senden eines Befehls einen Verbindungsaufbauversuch startet." en: "Automatically tries to reconnect if no response is received or connection is lost. This should not be necessary as the plugin always tries to reconnect before sending a command." - + item_attributes: avdevice_zone[0-4]: type: str description: de: 'Obiges Attribut muss mit dem Kommando ergänzt werden, das in der Text Datei hinterlegt ist, zB power oder volume' en: 'This attribute has to be followed by one of the commands declared in the device text file like power or volume' - diff --git a/avdevice/sc-lx86.txt b/avdevice/sc-lx86.txt index 7206df569..7910ac0ad 100755 --- a/avdevice/sc-lx86.txt +++ b/avdevice/sc-lx86.txt @@ -1,19 +1,35 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; MAXVALUE; RESPONSETYPE 1; power; on; PO|PO; ?P; PWR*; RW; yes 1; power; off; PF; ?P; PWR*; RW; yes -1; volume+; ; VU; ; VOL; W -1; volume-; ; VD; ; VOL; W +1; volume+; increase; VU; ; VOL; W +1; volume-; decrease; VD; ; VOL; W 1; volumehigh; ; 150VL; ?V; VOL150; W 1; volumelow; ; 110VL; ?V; VOL110; W 1; volume; set; ***VL; ?V; VOL***; RW; ; 161 1; mute; on; MO; ?M; MUT*; RW; yes 1; mute; off; MF; ?M; MUT*; RW; yes 1; mode; set; ****SR; ?S; SR****; RW +1; playingmode; ; ?L; ?L; LM****; R; ; ; str +1; speakers; set; *SPK; ?SPK; SPK*; RW 1; input; set; **FN; ?F; FN**; RW +1; tone; on; 1TO; ?TO; TO*; RW +1; tone; off; 0TO; ?TO; TO*; RW +1; bass; set; **BA; ?BA; BA**; RW; ; 12 +1; trebble; set; **TR; ?TR; TR**; RW; ; 12 +1; bass+; increase; BI; ; BA; W +1; bass-; decrease; BD; ; BA; W +1; trebble+; increase; TI; ; TR; W +1; trebble-; decrease; TD; ; TR; W +1; dialog; set; *ATH; ?ATH; ATH*; RW +1; HDMI; set; *HO; ?HO; HO*; RW +1; input+; increase; FU; ?F; FN; W +1; input-; decrease; FD; ?F; FN; W +1; radiof+; ; TPI; ; PR; W; ; ; str +1; radiof-; ; TPD; ; PR; W; ; ; str 2; power; on; APO|APO; ?AP; APR*; RW; yes 2; power; off; APF; ?AP; APR*; RW; yes -2; volume+; ; ZU; ; ZV; W -2; volume-; ; ZD; ; ZV; W +2; volume+; increase; ZU; ; ZV; W +2; volume-; decrease; ZD; ; ZV; W 2; volumehigh; ; 70ZV; ?ZV; ZV70; W 2; volumelow; ; 45ZV; ?ZV; ZV45; W 2; volume; set; **ZV; ?ZV; ZV**; RW; ; 81 @@ -22,8 +38,8 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; 2; input; set; **ZS; ?ZS; Z2F**; RW 3; power; on; BPO|BPO; ?BP; BPR*; RW; yes 3; power; off; BPF; ?BP; BPR*; RW; yes -3; volume+; ; YU; ; YV; W -3; volume-; ; YD; ; YV; W +3; volume+; increase; YU; ; YV; W +3; volume-; decrease; YD; ; YV; W 3; volumehigh; ; 75YV; ?YV; YV75; W 3; volumelow; ; 45YV; ?YV; YV45; W 3; volume; set; **YV; ?YV; YV**; RW; ; 81 @@ -33,7 +49,7 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; 4; power; on; ZEO; ?ZEP; ZEP*; RW; yes 4; power; off; ZEF; ?ZEP; ZEP*; RW; yes 4; input; set; **ZEA; ?ZEA; ZEA**; RW -0; title; ; ; ; GEH01020; R -0; station; ; ; ; GEH04022; R -0; genre; ; ; ; GEH05024; R +0; title; ; ; ; GEH01020; R; ; ; str +0; station; ; ; ; GEH04022; R; ; ; str +0; genre; ; ; ; GEH05024; R; ; ; str 0; display; ; ?FL; ?FL; FL******************************; R diff --git a/avdevice/vsx-923.txt b/avdevice/vsx-923.txt index 148f4656b..b2e8e9dbf 100755 --- a/avdevice/vsx-923.txt +++ b/avdevice/vsx-923.txt @@ -1,26 +1,42 @@ ZONE; FUNCTION; FUNCTIONTYPE; SEND; QUERY; RESPONSE; READWRITE; INVERTRESPONSE; MAXVALUE; RESPONSETYPE 1; power; on; PO|PO; ?P; PWR*; RW; yes 1; power; off; PF; ?P; PWR*; RW; yes -1; volume+; ; VU; ; VOL; W -1; volume-; ; VD; ; VOL; W +1; volume+; increase; VU; ; VOL; W +1; volume-; decrease; VD; ; VOL; W 1; volumehigh; ; 150VL; ?V; VOL150; W 1; volumelow; ; 110VL; ?V; VOL110; W 1; volume; set; ***VL; ?V; VOL***; RW; ; 185 1; mute; on; MO; ?M; MUT*; RW; yes 1; mute; off; MF; ?M; MUT*; RW; yes 1; input; set; **FN; ?F; FN**; RW +1; mode; set; ****SR; ?S; SR****; RW +1; playingmode; ; ?L; ?L; LM****; R; ; ; num +1; speakers; set; *SPK; ?SPK; SPK*; RW +1; tone; on; 1TO; ?TO; TO*; RW +1; tone; off; 0TO; ?TO; TO*; RW +1; bass; set; **BA; ?BA; BA**; RW; ; 12 +1; trebble; set; **TR; ?TR; TR**; RW; ; 12 +1; bass+; increase; BI; ; BA; W +1; bass-; decrease; BD; ; BA; W +1; trebble+; increase; TI; ; TR; W +1; trebble-; decrease; TD; ; TR; W +1; dialog; set; *ATH; ?ATH; ATH*; RW +1; HDMI; set; *HO; ?HO; HO*; RW +1; input+; increase; FU; ?F; FN; W +1; input-; decrease; FD; ?F; FN; W +1; radiof+; ; TPI; ; PR; W; ; ; str +1; radiof-; ; TPD; ; PR; W; ; ; str 2; power; on; APO|APO; ?AP; APR*; RW; yes 2; power; off; APF; ?AP; APR*; RW; yes -2; volume+; ; ZU; ; ZV; W -2; volume-; ; ZD; ; ZV; W +2; volume+; increase; ZU; ; ZV; W +2; volume-; decrease; ZD; ; ZV; W 2; volumehigh; ; 75ZV; ?ZV; ZV75; W 2; volumelow; ; 45ZV; ?ZV; ZV45; W 2; volume; set; **ZV; ?ZV; ZV**; RW; ; 81 2; mute; on; Z2MO; ?Z2M; Z2MUT*; RW; yes 2; mute; off; Z2MF; ?Z2M; Z2MUT*; RW; yes 2; input; set; **ZS; ?ZS; Z2F**; RW -0; title; ; ; ; GEH01020; R -0; station; ; ; ; GEH04022; R -0; genre; ; ; ; GEH05024; R +0; title; ; ; ; GEH01020; R; ; ; str +0; station; ; ; ; GEH04022; R; ; ; str +0; genre; ; ; ; GEH05024; R; ; ; str 0; display; ; ?FL; ?FL; FL******************************; R -1; speakers; set; *SPK; ?SPK; SPK*; RW diff --git a/backend/BackendItems.py b/backend/BackendItems.py index 75aef066d..dd9487d82 100755 --- a/backend/BackendItems.py +++ b/backend/BackendItems.py @@ -342,6 +342,7 @@ def item_detail_json_html(self, item_path): 'config': json.dumps(item_conf_sorted), 'logics': json.dumps(logics), 'triggers': json.dumps(triggers), + 'filename': str(item._filename), } # cast raw data to a string diff --git a/backend/BackendLogging.py b/backend/BackendLogging.py index c6cb819e6..945f08f8c 100755 --- a/backend/BackendLogging.py +++ b/backend/BackendLogging.py @@ -79,8 +79,11 @@ def logging_html(self): except: fn = '' l['filenames'].append(fn) - - loggers.append(l) + + if l['handlers'] == ['NullHandler']: + self.logger.warning("logging_html: Filtered out logger {}: l['handlers'] = {}".format(l['name'], l['handlers'])) + else: + loggers.append(l) return self.render_template('logging.html', loggers=loggers) diff --git a/backend/BackendSysteminfo.py b/backend/BackendSysteminfo.py index 89f16a449..5d22dd3f4 100755 --- a/backend/BackendSysteminfo.py +++ b/backend/BackendSysteminfo.py @@ -96,7 +96,7 @@ def system_html(self): #req_dict = self.get_requirements_info() return self.render_template('system.html', - now=now, system=system, sh_vers=shngversion.get_shng_version(), plg_vers=shngversion.get_plugins_version(), sh_dir=self._sh_dir, + now=now, system=system, sh_vers=shngversion.get_shng_version(), sh_desc=shngversion.get_shng_description(), plg_vers=shngversion.get_plugins_version(), plg_desc=shngversion.get_plugins_description(), sh_dir=self._sh_dir, vers=vers, node=node, arch=arch, user=user, freespace=freespace, uptime=uptime, sh_uptime=sh_uptime, pyversion=pyversion, ip=ip, ipv6=ipv6) @@ -261,7 +261,7 @@ def pypi_json(self): package['sort'] = '3' else: package['sort'] = '4' - self.logger.info("pypi_json: sort=4, package['name'] = >{}<".format(package['name'])) + self.logger.debug("pypi_json: sort=4, package['name'] = >{}<".format(package['name'])) package['sort'] += package['name'] @@ -578,7 +578,7 @@ def check_requirement(self, package, req_str): # Now we have a list of [ requirement_source, min_version (with operator), max_version (with operator) ] if len(req_result) == 1: result = req_result[0] - self.logger.info("check_requirement: package {}, req_result = >{}<, result = >{}<".format(package, req_result, result)) + self.logger.debug("check_requirement: package {}, req_result = >{}<, result = >{}<".format(package, req_result, result)) #handle min op, req_min = self.split_operator(result[1]) if req_min == '*': diff --git a/backend/BackendThreads.py b/backend/BackendThreads.py index f7514de00..bb68c1be5 100755 --- a/backend/BackendThreads.py +++ b/backend/BackendThreads.py @@ -39,7 +39,7 @@ def thread_sum(self, name, count): thread['name'] = name thread['sort'] = str(thread['name']).lower() thread['id'] = "(" + str(count) + " threads" + ")" - thread['alive'] = 'Ja' + thread['alive'] = 'True' return thread @cherrypy.expose @@ -68,9 +68,9 @@ def threads_html(self): thread['id'] = t.ident try: if t.is_alive(): - thread['alive'] = 'Ja' + thread['alive'] = 'True' else: - thread['alive'] = 'Nein' + thread['alive'] = 'False' except AssertionError: thread['alive'] = 'AssertionError' diff --git a/backend/__init__.py b/backend/__init__.py index 8896cd413..60b86f061 100755 --- a/backend/__init__.py +++ b/backend/__init__.py @@ -50,7 +50,7 @@ class BackendServer(SmartPlugin): the update functions for the items """ - PLUGIN_VERSION='1.4.8' + PLUGIN_VERSION='1.4.9' def __init__(self, sh, updates_allowed='True', developer_mode="no", pypi_timeout=5): diff --git a/backend/locale/de.json b/backend/locale/de.json index 7858c966b..df17f0618 100755 --- a/backend/locale/de.json +++ b/backend/locale/de.json @@ -205,7 +205,8 @@ "cycle": "cycle", "crontab": "crontab", "autotimer": "autotimer", - "threshold": "threshold" + "threshold": "threshold", + "filename": "definiert in" }, "_threads": { diff --git a/backend/locale/en.json b/backend/locale/en.json index ba0fc8d34..08946ddcf 100755 --- a/backend/locale/en.json +++ b/backend/locale/en.json @@ -205,7 +205,8 @@ "cycle": "cycle", "crontab": "crontab", "autotimer": "autotimer", - "threshold": "threshold" + "threshold": "threshold", + "filename": "defined in" }, "_threads": { diff --git a/backend/locale/fr.json b/backend/locale/fr.json index ffee4fc9d..32b84158f 100755 --- a/backend/locale/fr.json +++ b/backend/locale/fr.json @@ -207,7 +207,8 @@ "cycle": "cycle", "crontab": "crontab", "autotimer": "autotimer", - "threshold": "threshold" + "threshold": "threshold", + "filename": "" }, "_threads": { diff --git a/backend/locale/pl.json b/backend/locale/pl.json index 84fc594bc..07c1935f3 100755 --- a/backend/locale/pl.json +++ b/backend/locale/pl.json @@ -203,7 +203,8 @@ "cycle": "cykl", "crontab": "harmonogram", "autotimer": "autotimer", - "threshold": "próg" + "threshold": "próg", + "filename": "" }, "_threads": { diff --git a/backend/plugin.yaml b/backend/plugin.yaml index 5c9248473..86ac201fe 100755 --- a/backend/plugin.yaml +++ b/backend/plugin.yaml @@ -12,8 +12,8 @@ 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/959964-support-thread-für-das-backend-plugin - version: 1.4.8 # Plugin version - sh_minversion: 1.3d # minimum shNG version to use this plugin + version: 1.4.9 # Plugin version + sh_minversion: 1.4a # 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 classname: BackendServer # class containing the plugin diff --git a/backend/webif/templates/items.html b/backend/webif/templates/items.html index 2bbe8abb8..4bf9f508e 100755 --- a/backend/webif/templates/items.html +++ b/backend/webif/templates/items.html @@ -49,6 +49,12 @@ case 'str': var input = ''; break; + case 'list': + var input = ''; + break; + case 'dict': + var input = ''; + break; case 'num': var input = ''; break; @@ -118,6 +124,10 @@ temp = temp + '