<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.domoticz.com/index.php?action=history&amp;feed=atom&amp;title=Plugins%2FSoundtouch</id>
	<title>Plugins/Soundtouch - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.domoticz.com/index.php?action=history&amp;feed=atom&amp;title=Plugins%2FSoundtouch"/>
	<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Plugins/Soundtouch&amp;action=history"/>
	<updated>2026-09-18T22:42:25Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>https://wiki.domoticz.com/index.php?title=Plugins/Soundtouch&amp;diff=14134&amp;oldid=prev</id>
		<title>Rwaaren: set Python as source language</title>
		<link rel="alternate" type="text/html" href="https://wiki.domoticz.com/index.php?title=Plugins/Soundtouch&amp;diff=14134&amp;oldid=prev"/>
		<updated>2020-05-03T21:58:49Z</updated>

		<summary type="html">&lt;p&gt;set Python as source language&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Bose soundtouch devices and be controlled directly using the network connection. For this, a python library is available called libsoundtouch (https://github.com/CharlesBlonde/libsoundtouch)&lt;br /&gt;
&lt;br /&gt;
This plugin uses this library to control the device. &lt;br /&gt;
&lt;br /&gt;
===Installation===&lt;br /&gt;
For this plugin, you will need:&lt;br /&gt;
&lt;br /&gt;
*Libsoundtouch library - if you use &amp;quot;pip install libsoundtouch&amp;quot;, the 2.7 python module will be installed. As Domoticz runs under python 3, this will not work. Use &amp;quot;python3 -m pip install libsoundtouch&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*- zeroconf library  - if not installed, use &amp;quot;python3 -m pip install zeroconf&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*- websocket library - if not installed, use &amp;quot;python3 -m pip install websocket&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*install the plugin (see section plugin)&lt;br /&gt;
&lt;br /&gt;
===Usage===&lt;br /&gt;
After installation of the plugin, a hardware device called &amp;quot;Soundtouch plugin&amp;quot; should be available in domoticz. There are the following parameters:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Parameter&lt;br /&gt;
!Value&lt;br /&gt;
!Purpose&lt;br /&gt;
|-&lt;br /&gt;
|Soundtouch host&lt;br /&gt;
|IP/DNS name&lt;br /&gt;
|The IP or DNS name of the soundtouch device&lt;br /&gt;
|-&lt;br /&gt;
|Interval&lt;br /&gt;
|seconds&lt;br /&gt;
|Used to query the device periodically to update the volume/station in domiticz. Note that this is only needed if the device is controlled directly&lt;br /&gt;
|-&lt;br /&gt;
|Automatic presets&lt;br /&gt;
|True/False&lt;br /&gt;
|On startup if this option is True, the presets are read from the device and the control device is updated with preset station names. Disable if you want to name it manually.&lt;br /&gt;
|-&lt;br /&gt;
|Debug&lt;br /&gt;
|True/False&lt;br /&gt;
|Default, false. If set to true, a logfile is generated in the plugin folder and the domoticz log is written to with additional information&lt;br /&gt;
|}&lt;br /&gt;
There are two devices added on startup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[File:2020-04-29 14-28-43.gif|thumb|Soundtouch plugin devices |alt=|border|left]]&lt;br /&gt;
&lt;br /&gt;
Control -  Used to change the preset&lt;br /&gt;
&lt;br /&gt;
Volume - Control the volume. &lt;br /&gt;
&lt;br /&gt;
If the interval is set, any change on the device will be reflected in these controls periodically.   &lt;br /&gt;
&lt;br /&gt;
===Plugin===&lt;br /&gt;
Create a folder in the domoticz plugin folder, Soundtouch. Eg. /home/pi/domoticz/plugins/Soundtouch. Create a file, python.py in this folder with this content:&lt;br /&gt;
 &amp;lt;source lang=&amp;quot;Python&amp;quot;&amp;gt;&lt;br /&gt;
 # Soundtouch plugin&lt;br /&gt;
 #&lt;br /&gt;
 # Author: Gerrit Hulleman&lt;br /&gt;
 #&lt;br /&gt;
 &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 &amp;lt;plugin key=&amp;quot;SoundTouch&amp;quot; name=&amp;quot;Soundtouch plugin&amp;quot; author=&amp;quot;Gerrit Hulleman&amp;quot; version=&amp;quot;1.0.1&amp;quot; wikilink=&amp;quot;http://www.domoticz.com/wiki/plugins/plugin.html&amp;quot; externallink=&amp;quot;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;description&amp;gt;&lt;br /&gt;
        &amp;lt;h2&amp;gt;Soundtouch plugin&amp;lt;/h2&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
        Uses the libsoundtouch (https://github.com/CharlesBlonde/libsoundtouch) to communicate with bose soundtouch devices. &lt;br /&gt;
        &amp;lt;h3&amp;gt;Features&amp;lt;/h3&amp;gt;&lt;br /&gt;
        &amp;lt;ul style=&amp;quot;list-style-type:square&amp;quot;&amp;gt;            &lt;br /&gt;
              &amp;lt;li&amp;gt;Turn off / switch preset stations&amp;lt;/li&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;Control audio&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
        &amp;lt;h3&amp;gt;Configuration&amp;lt;/h3&amp;gt;&lt;br /&gt;
        Soundtouch host: the IP/DNS name of the soundtouch device&lt;br /&gt;
        Interval: active reread of device status. Note: only needed if the device op operated directly&lt;br /&gt;
        Automatic presets: use preset in device to update control.&lt;br /&gt;
        Debug: additional debug information to domoticz log and logfile. &lt;br /&gt;
    &amp;lt;/description&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Address&amp;quot; label=&amp;quot;Soundtouch host&amp;quot; width=&amp;quot;200px&amp;quot; required=&amp;quot;true&amp;quot; default=&amp;quot;192.168.178.24&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode1&amp;quot; label=&amp;quot;Interval&amp;quot; width=&amp;quot;200px&amp;quot; required=&amp;quot;true&amp;quot; default=&amp;quot;10&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode2&amp;quot; label=&amp;quot;Automatic presets&amp;quot; width=&amp;quot;75px&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;options&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;True&amp;quot; value=&amp;quot;1&amp;quot; default=&amp;quot;true&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;False&amp;quot; value=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
            &amp;lt;/options&amp;gt;&lt;br /&gt;
        &amp;lt;/param&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
        &amp;lt;param field=&amp;quot;Mode6&amp;quot; label=&amp;quot;Debug&amp;quot; width=&amp;quot;75px&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;options&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;True&amp;quot; value=&amp;quot;Debug&amp;quot;/&amp;gt;&lt;br /&gt;
                &amp;lt;option label=&amp;quot;False&amp;quot; value=&amp;quot;Normal&amp;quot;  default=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
            &amp;lt;/options&amp;gt;&lt;br /&gt;
        &amp;lt;/param&amp;gt;&lt;br /&gt;
        &lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
 &amp;lt;/plugin&amp;gt;&lt;br /&gt;
 &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
 import Domoticz&lt;br /&gt;
 import sys&lt;br /&gt;
 sys.path.append(&amp;#039;/home/pi/.local/lib/python3.7/site-packages/&amp;#039;)&lt;br /&gt;
 &lt;br /&gt;
 from libsoundtouch import soundtouch_device&lt;br /&gt;
 from libsoundtouch.utils import Source, Type&lt;br /&gt;
 &lt;br /&gt;
 class BasePlugin:&lt;br /&gt;
    enabled = False&lt;br /&gt;
    debugMode = False&lt;br /&gt;
    soundTouchHost = &amp;#039;&amp;#039;&lt;br /&gt;
    deviceName = &amp;#039;&amp;#039;&lt;br /&gt;
    heartbeat = 10&lt;br /&gt;
    automaticPreset = False&lt;br /&gt;
    presetMap = {} #Contains location / preset id on startup&lt;br /&gt;
 &lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        return&lt;br /&gt;
 &lt;br /&gt;
    def onStart(self):&lt;br /&gt;
        self.logMessage(&amp;quot;Loading parameters&amp;quot;)&lt;br /&gt;
        self.soundTouchHost = Parameters[&amp;quot;Address&amp;quot;]&lt;br /&gt;
        self.heartbeat = Parameters[&amp;quot;Mode1&amp;quot;]&lt;br /&gt;
        if Parameters[&amp;quot;Mode2&amp;quot;] != &amp;quot;0&amp;quot;:&lt;br /&gt;
            self.automaticPreset = True&lt;br /&gt;
        if Parameters[&amp;quot;Mode6&amp;quot;] != &amp;quot;Debug&amp;quot;:&lt;br /&gt;
            Domoticz.Debugging(0)&lt;br /&gt;
            self.debugMode = False&lt;br /&gt;
        else:&lt;br /&gt;
            self.debugMode = True&lt;br /&gt;
        if (self.heartbeat != 0):&lt;br /&gt;
            Domoticz.Heartbeat(int(self.heartbeat))&lt;br /&gt;
            &lt;br /&gt;
        if (len(Devices) == 0):&lt;br /&gt;
            # devices not created, possible first run or deleted.&lt;br /&gt;
            Options = {&amp;quot;LevelActions&amp;quot;: &amp;quot;||||&amp;quot;,&lt;br /&gt;
                       &amp;quot;LevelNames&amp;quot;: &amp;quot;Off|Preset 1|Preset 2|Preset 3|Preset 4&amp;quot;,&lt;br /&gt;
                       &amp;quot;LevelOffHidden&amp;quot;: &amp;quot;false&amp;quot;,&lt;br /&gt;
                       &amp;quot;SelectorStyle&amp;quot;: &amp;quot;1&amp;quot;}&lt;br /&gt;
            Domoticz.Device(Name=&amp;quot;control&amp;quot;, Unit=1, TypeName=&amp;quot;Selector Switch&amp;quot;, Options=Options, Image=8).Create() # Image 8 = speaker icon&lt;br /&gt;
            Domoticz.Device(Name=&amp;quot;volume&amp;quot;, Unit=2, TypeName=&amp;quot;Switch&amp;quot;, Switchtype=7, Image=8).Create() # Switchtype 7 = dimmer, Image 8 = speaker icon&lt;br /&gt;
            self.logMessage(&amp;quot;Soundtouch devices created&amp;quot;);            &lt;br /&gt;
            &lt;br /&gt;
 &lt;br /&gt;
        extDevice = soundtouch_device(self.soundTouchHost)&lt;br /&gt;
        presets = extDevice.presets()&lt;br /&gt;
        presetOptions = &amp;quot;Off&amp;quot;&lt;br /&gt;
        presetActions = &amp;quot;&amp;quot;&lt;br /&gt;
        for preset in presets:&lt;br /&gt;
            presetOptions += &amp;#039;|&amp;#039;&lt;br /&gt;
            presetActions += &amp;#039;|&amp;#039;&lt;br /&gt;
            presetOptions += preset.name&lt;br /&gt;
            # save location. If the channel is change on the device, easier lookup on heartbeat&lt;br /&gt;
            presetIdSwitch = int(preset.preset_id)*10; # 1 = 10, 2 = 20 etc. &lt;br /&gt;
            self.presetMap[preset.location] = presetIdSwitch&lt;br /&gt;
            self.logDebug(&amp;quot;Channel: &amp;quot;+preset.name+ &amp;quot; id: &amp;quot;+str(preset.preset_id)+ &amp;quot; selector: &amp;quot;+str(presetIdSwitch))&lt;br /&gt;
                &lt;br /&gt;
        if (self.automaticPreset):&lt;br /&gt;
            self.logMessage(&amp;quot;Preset update - auto : &amp;quot; + presetOptions)            &lt;br /&gt;
                &lt;br /&gt;
            Options = {&amp;quot;LevelActions&amp;quot;: presetActions,&lt;br /&gt;
                       &amp;quot;LevelNames&amp;quot;: presetOptions,&lt;br /&gt;
                       &amp;quot;LevelOffHidden&amp;quot;: &amp;quot;false&amp;quot; }&lt;br /&gt;
            # nValue/sValue is mandatory.&lt;br /&gt;
            Devices[1].Update(nValue=Devices[1].nValue, sValue=Devices[1].sValue, Options=Options)&lt;br /&gt;
        &lt;br /&gt;
        self.logMessage(&amp;quot;Plugin operational&amp;quot;)&lt;br /&gt;
    def onStop(self):&lt;br /&gt;
        self.logDebug(&amp;quot;onStop called&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
    def onConnect(self, Connection, Status, Description):&lt;br /&gt;
        self.logDebug(&amp;quot;onConnect called&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
    def onMessage(self, Connection, Data):&lt;br /&gt;
        self.logDebug(&amp;quot;onMessage called&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
    def onCommand(self, Unit, Command, Level, Hue):        &lt;br /&gt;
        self.logDebug(&amp;quot;onCommand called for Unit &amp;quot; + str(Unit) + &amp;quot;: Command &amp;#039;&amp;quot; + str(Command) + &amp;quot;&amp;#039;, Level: &amp;quot; + str(Level))&lt;br /&gt;
        #(Bose 20) onCommand called for Unit 1: Parameter &amp;#039;Set Level&amp;#039;, Level: 10&lt;br /&gt;
        if (Unit == 1):&lt;br /&gt;
            # control device&lt;br /&gt;
            if (Command == &amp;quot;Set Level&amp;quot;):&lt;br /&gt;
                extDevice = soundtouch_device(self.soundTouchHost)&lt;br /&gt;
                if Level == 0:&lt;br /&gt;
                    extDevice.power_off()&lt;br /&gt;
                presetId = int((Level / 10) - 1)&lt;br /&gt;
                if (presetId &amp;gt;= 0&lt;br /&gt;
                and presetId &amp;lt;= 6):&lt;br /&gt;
                    presets = extDevice.presets()&lt;br /&gt;
                    extDevice.select_preset(presets[presetId])&lt;br /&gt;
                Devices[1].Update(2, str(Level)) # switch is not updated from domoticz itself. &lt;br /&gt;
            if (Command == &amp;quot;Off&amp;quot;):&lt;br /&gt;
                extDevice = soundtouch_device(self.soundTouchHost)&lt;br /&gt;
                extDevice.power_off()&lt;br /&gt;
                Devices[1].Update(2, str(Level)) # switch is not updated from domoticz itself. &lt;br /&gt;
        #(Bose 20) onCommand called for Unit 2: Command &amp;#039;Set Level&amp;#039;, Level: 17&lt;br /&gt;
        if (Unit == 2):&lt;br /&gt;
            # volume control&lt;br /&gt;
            extDevice = soundtouch_device(self.soundTouchHost)&lt;br /&gt;
            if (Command == &amp;quot;Off&amp;quot;):&lt;br /&gt;
                extDevice.set_volume(0)&lt;br /&gt;
                Devices[2].Update(0, str(Level)) # switch is not updated from domoticz itself. &lt;br /&gt;
            else:&lt;br /&gt;
                extDevice.set_volume(Level)&lt;br /&gt;
                Devices[2].Update(2, str(Level)) # switch is not updated from domoticz itself. &lt;br /&gt;
            &lt;br /&gt;
    def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile):&lt;br /&gt;
        self.logDebug(&amp;quot;Notification: &amp;quot; + Name + &amp;quot;,&amp;quot; + Subject + &amp;quot;,&amp;quot; + Text + &amp;quot;,&amp;quot; + Status + &amp;quot;,&amp;quot; + str(Priority) + &amp;quot;,&amp;quot; + Sound + &amp;quot;,&amp;quot; + ImageFile)&lt;br /&gt;
 &lt;br /&gt;
    def onDisconnect(self, Connection):&lt;br /&gt;
        self.logDebug(&amp;quot;Disconnect&amp;quot;)&lt;br /&gt;
        return&lt;br /&gt;
 &lt;br /&gt;
    def onHeartbeat(self):&lt;br /&gt;
        self.logDebug(&amp;quot;onHeartbeat called&amp;quot;)&lt;br /&gt;
        extDevice = soundtouch_device(self.soundTouchHost)&lt;br /&gt;
        try:&lt;br /&gt;
            # check/update station&lt;br /&gt;
            status = extDevice.status()&lt;br /&gt;
            # print(status.source) # TUNEIN, STANDBY, BLUETOOTH, AUX&lt;br /&gt;
            if (status.source == &amp;quot;STANDBY&amp;quot;):&lt;br /&gt;
                self.logDebug(&amp;quot;on standby&amp;quot;)&lt;br /&gt;
                Devices[1].Update(nValue = 0, sValue = &amp;quot;00&amp;quot;)&lt;br /&gt;
                self.logDebug(&amp;quot;Device updated&amp;quot;)&lt;br /&gt;
            else:&lt;br /&gt;
                location = status.content_item.location&lt;br /&gt;
                if (location in self.presetMap):&lt;br /&gt;
                    # found -&amp;gt; update device to reflect channel&lt;br /&gt;
                    #self.logDebug(&amp;quot;Found channel currently on &amp;quot; + str(self.presetMap[location]))&lt;br /&gt;
                    Devices[1].Update(2, sValue = str(self.presetMap[location]))&lt;br /&gt;
                &lt;br /&gt;
                # check/update volume&lt;br /&gt;
                actualVolume = extDevice.volume().actual&lt;br /&gt;
                self.logDebug(&amp;quot;Set volume: &amp;quot; + str(actualVolume))&lt;br /&gt;
                Devices[2].Update(2, str(actualVolume))&lt;br /&gt;
                self.logDebug(&amp;quot;Set volume done&amp;quot;)&lt;br /&gt;
        except:&lt;br /&gt;
            self.logMessage(&amp;quot;Unexpected error:&amp;quot; + sys.exc_info()[0])&lt;br /&gt;
        self.logDebug(&amp;quot;Heartbeat done, return&amp;quot;)        &lt;br /&gt;
    &lt;br /&gt;
    def logMessage(self, Message):        &lt;br /&gt;
        if self.debugMode:&lt;br /&gt;
            f= open(&amp;quot;plugins/Soundtouch/log.txt&amp;quot;,&amp;quot;a+&amp;quot;)&lt;br /&gt;
            f.write(Message+&amp;#039;\r\n&amp;#039;)&lt;br /&gt;
        Domoticz.Log(Message)&lt;br /&gt;
        &lt;br /&gt;
    def logDebug(self, Message):        &lt;br /&gt;
        if self.debugMode:&lt;br /&gt;
            self.logMessage(Message)&lt;br /&gt;
        &lt;br /&gt;
 global _plugin&lt;br /&gt;
 _plugin = BasePlugin()&lt;br /&gt;
 &lt;br /&gt;
 def onStart():&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onStart()&lt;br /&gt;
 &lt;br /&gt;
 def onStop():&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onStop()&lt;br /&gt;
 &lt;br /&gt;
 def onConnect(Connection, Status, Description):&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onConnect(Connection, Status, Description)&lt;br /&gt;
 &lt;br /&gt;
 def onMessage(Connection, Data):&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onMessage(Connection, Data)&lt;br /&gt;
 &lt;br /&gt;
 def onCommand(Unit, Command, Level, Hue):&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onCommand(Unit, Command, Level, Hue)&lt;br /&gt;
 &lt;br /&gt;
 def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile)&lt;br /&gt;
 &lt;br /&gt;
 def onDisconnect(Connection):&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onDisconnect(Connection)&lt;br /&gt;
 &lt;br /&gt;
 def onHeartbeat():&lt;br /&gt;
    global _plugin&lt;br /&gt;
    _plugin.onHeartbeat()&lt;br /&gt;
 &lt;br /&gt;
    # Generic helper functions&lt;br /&gt;
 def DumpConfigToLog():&lt;br /&gt;
    for x in Parameters:&lt;br /&gt;
        if Parameters[x] != &amp;quot;&amp;quot;:&lt;br /&gt;
            Domoticz.Log( &amp;quot;&amp;#039;&amp;quot; + x + &amp;quot;&amp;#039;:&amp;#039;&amp;quot; + str(Parameters[x]) + &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
    Domoticz.Log(&amp;quot;Device count: &amp;quot; + str(len(Devices)))&lt;br /&gt;
    for x in Devices:&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device:           &amp;quot; + str(x) + &amp;quot; - &amp;quot; + str(Devices[x]))&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device ID:       &amp;#039;&amp;quot; + str(Devices[x].ID) + &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device UnitID:   &amp;#039;&amp;quot; + str(Devices[x].Unit) + &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device DeviceID: &amp;#039;&amp;quot; + str(Devices[x].DeviceID) + &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device Name:     &amp;#039;&amp;quot; + Devices[x].Name + &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device nValue:    &amp;quot; + str(Devices[x].nValue))&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device sValue:   &amp;#039;&amp;quot; + Devices[x].sValue + &amp;quot;&amp;#039;&amp;quot;)&lt;br /&gt;
        Domoticz.Log(&amp;quot;Device LastLevel: &amp;quot; + str(Devices[x].LastLevel))&lt;br /&gt;
    return&lt;br /&gt;
 &amp;lt;/source&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
===Errors===&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;Invalid syntax&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039; &lt;br /&gt;
&lt;br /&gt;
File &amp;quot;bose.py&amp;quot;, line 7, in &amp;lt;module&amp;gt;&lt;br /&gt;
from libsoundtouch import soundtouch_device&lt;br /&gt;
File &amp;quot;/usr/local/lib/python2.7/dist-packages/libsoundtouch/__init__.py&amp;quot;, line 9, in &amp;lt;module&amp;gt;&lt;br /&gt;
from zeroconf import Zeroconf, ServiceBrowser&lt;br /&gt;
File &amp;quot;/usr/local/lib/python2.7/dist-packages/zeroconf.py&amp;quot;, line 175&lt;br /&gt;
def current_time_millis() -&amp;gt; float:&lt;br /&gt;
^&lt;br /&gt;
&lt;br /&gt;
SyntaxError: invalid syntax&lt;br /&gt;
&lt;br /&gt;
For those who got this error: check the python version (terminal, python -V). If version 2.7.x, zeroconf might be a high version (terminal, pip show zeroconf). Version 0.20 and higher does not support python 2.7. If you want to use python 2.7, uninstall zerconf (pip uninstall zeroconf) and install version 0.19.1 (pip install zeroconf==0.19.1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;Error: ...... hardware (##) thread seems to have ended unexpectedly&amp;#039;&amp;#039;&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
Unknown. The heartbeat is finished with updating the controls and without error according to the log (added in v1.0.1). But still Domoticz reports this error. &amp;lt;br /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Rwaaren</name></author>
	</entry>
</feed>