What works is sending pakets for controling but when i uncomment python self._event_loop.create_task(self._receive_data())
home assistant either completly locks up or does not finish startup until 5 minutes pass where it times out. The api sends a tcp packet for every cahnge for the topics your subscribed to. Here is the documentation from the api: https://bssaudio.com/en/site_elements/soundweb-london-third-party-control-application-guide
And here is my code i have so far:
import logging
import voluptuous as vol
import socket
import asyncio
from json import loads, dumps
#from datetime import timedelta
import homeassistant.helpers.config_validation as cv
from homeassistant.components.media_player import (
MediaPlayerEntity,
PLATFORM_SCHEMA,
SUPPORT_SELECT_SOURCE,
SUPPORT_VOLUME_MUTE,
SUPPORT_VOLUME_SET,
SUPPORT_VOLUME_STEP,
)
from homeassistant.const import (
CONF_NAME,
STATE_IDLE,
STATE_PLAYING,
STATE_PAUSED,
STATE_OFF,
)
node = '\x00\x01'
device = '\x03'
parameterR1 = '\x00\x01'
parameterL1 = '\x00\x00'
muteparameterR1 = '\x00\x21'
muteparameterL1 = '\x00\x20'
ip_address = "10.10.12.86"
port = 1023
_LOGGER = logging.getLogger(__name__)
#SCAN_INTERVAL = timedelta(seconds=10)
#CUSTOMIZE_SCHEMA = vol.Schema(
# {vol.Optional(CONF_SOURCES): vol.All(cv.ensure_list, [cv.string])}
#)
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_NAME, default='My Media Player'): cv.string,
vol.Required("object_id"): cv.string,
vol.Required("zone_idL"): cv.string,
vol.Required("zone_idR"): cv.string,
vol.Required("meter_playing_id"): cv.string,
vol.Optional("source", default='Sundeck'): vol.In(['Sundeck', 'Owners Cabin', 'Loft', 'Bar', 'Winter Garden', 'Heli Hangar', 'Lazarette', 'DJ']),
}
)
async def async_setup_platform(hass, config, add_entities, discovery_info=None):
name = config.get(CONF_NAME)
object_id = config["object_id"]
zone_idL = config["zone_idL"]
zone_idR = config["zone_idR"]
sources = config["source"]
meter = config["meter_playing_id"]
socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket1.connect((ip_address, port))
add_entities([BSSDevice(name,object_id,zone_idL,zone_idR,meter,sources,socket1,hass,muteparameterL1)], True)
def encodewithoutsubstitution(input: str):
output = b''
for x in input:
temp = bytes(x, 'utf-8')
if(int.from_bytes(temp,"big")>50047):
i = int.from_bytes(temp,"big") - 49856
output += i.to_bytes(1,"little")
elif(len(temp)!=1):
output += temp[1:2]
else:
output += temp
return output
def encode(input: str):
output = b''
for x in input:
temp = bytes(x, 'utf-8')
if(int.from_bytes(temp,"big")>50047):
i = int.from_bytes(temp,"big") - 49856
output += i.to_bytes(1,"little")
elif(len(temp)!=1):
output += temp[1:2]
elif(temp==b'\x02'):
output += b'\x1b\x82'
elif(temp==b'\x03'):
output += b'\x1b\x83'
elif(temp==b'\x06'):
output += b'\x1b\x86'
elif(temp==b'\x15'):
output += b'\x1b\x95'
elif(temp==b'\x1b'):
output += b'\x1b\x9b'
else:
output += temp
return output
def decode(input: bytes):
temp = input
while(len(temp)>16):
if(b'\x1b\x82' in temp):
temp = temp[0:temp.find(b'\x1b\x82')] + b'\x02' + temp[temp.find(b'\x1b\x82')+2:len(temp)]
elif(b'\x1b\x83' in temp):
temp = temp[0:temp.find(b'\x1b\x83')] + b'\x03' + temp[temp.find(b'\x1b\x83')+2:len(temp)]
elif(b'\x1b\x86' in temp):
temp = temp[0:temp.find(b'\x1b\x86')] + b'\x06' + temp[temp.find(b'\x1b\x86')+2:len(temp)]
elif(b'\x1b\x95' in temp):
temp = temp[0:temp.find(b'\x1b\x95')] + b'\x15' + temp[temp.find(b'\x1b\x95')+2:len(temp)]
elif(b'\x1b\x9b' in temp):
temp = temp[0:temp.find(b'\x1b\x9b')] + b'\x1b' + temp[temp.find(b'\x1b\x9b')+2:len(temp)]
return temp
def bytetoint(negative: bytes, input: bytes):
if(negative==b'\xff'):
return -(16777216-int.from_bytes(input,"big"))
return int.from_bytes(input,"big")
def getvalue(input: bytes):
return bytetoint(decode(input)[10:11],decode(input)[11:14])
def getvolumepercent(input: bytes):
return (int)(bytetoint(decode(input)[10:11],decode(input)[11:14])/65536)
def send(input: bytes, socket1):
socket1.sendall(input)
def buildunsubscribepacket(messagetype: bytes, object: bytes, parameter: bytes):
combine = messagetype + node + device + object + parameter
checksum = 0
for el in combine:
checksum ^= ord(el)
end = b'\x02' + encode(combine) + encode(chr(checksum)) + b'\x03'
return end
def buildpacket(messagetype: bytes, object: bytes, parameter: bytes, value: int,special: int):
if(special==1):
volume_array = [255,256-value,0,0]
elif(special==0):
volume_array = [0,value,0,0]
elif(special==2):
volume_array = [0,0,0,value]
elif(special==3):
volume_array = [0,0,29,value]
value = ''
for i in volume_array:
value += chr(i)
combine = messagetype + node + device + object + parameter + value
checksum = 0
for el in combine:
checksum ^= ord(el)
end = b'\x02' + encode(combine) + encode(chr(checksum)) + b'\x03'
return end
def setmute(object: bytes, mute: bool,socket1):
if(mute):
send(buildpacket('\x88',object,muteparameterL1,1,2),socket1)
send(buildpacket('\x88',object,muteparameterR1,1,2),socket1)
else:
send(buildpacket('\x88',object,muteparameterL1,0,2),socket1)
send(buildpacket('\x88',object,muteparameterR1,0,2),socket1)
def setprecentpacket(object: bytes, value: int,socket1):
send(buildpacket('\x8d',object,parameterL1,value,0),socket1)
send(buildpacket('\x8d',object,parameterR1,value,0),socket1)
def bumpprecentpacket(object: bytes, value: int, negative: bool,socket1):
if(value==0):
return
if(negative):
send(buildpacket('\x90',object,parameterL1,value,1),socket1)
send(buildpacket('\x90',object,parameterR1,value,1),socket1)
else:
send(buildpacket('\x90',object,parameterL1,value,0),socket1)
send(buildpacket('\x90',object,parameterR1,value,0),socket1)
def setsource(object: bytes, value: int,socket1):
send(buildpacket('\x88',object,parameterL1,value,2),socket1)
def submute(object: bytes,socket1):
send(buildpacket('\x89',object,muteparameterR1,0,2),socket1)
#return getmuteresponse(object,socket1)
def submeter(object: bytes,socket1):
send(buildpacket('\x89',object,parameterL1,17,3),socket1)
#return getmeterresponse(object,socket1)
def subinput(object: bytes,socket1):
send(buildpacket('\x89',object,parameterL1,0,2),socket1)
#return getinputresponse(object,socket1)
def subvolume(object: bytes,socket1):
send(buildpacket('\x8e',object,parameterL1,0,2),socket1)
#return getvolumeresponse(object,socket1)/100
class BSSDevice(MediaPlayerEntity):
def __init__(self, name, object_id, zone_idL,zone_idR, meter, sources, socket1,loop,muteparameter):
self._name = name
self._object_id = object_id
self._zone_idL = zone_idL
self._zone_idR = zone_idR
self._meter = meter
self._source_list = sources
self._socket = socket1
self._event_loop = loop
self._muteparameter = muteparameter
self._is_mute = True
self._volume = 0.3
self._source = "Sundeck"
self._state = STATE_IDLE
#self._is_mute = submute(self._object_id,self._socket)
#self._source = subinput(self._zone_idL,self._socket)
#self._state = submeter(self._meter,self._socket)
#self._state = STATE_IDLE
self._loop = None
#self._volume = subvolume(self._object_id,self._socket)/100
self._is_subscribed = False
#self._event_loop.async_add_executor_job()
@property
def supported_features(self):
return SUPPORT_VOLUME_SET | SUPPORT_VOLUME_STEP | SUPPORT_SELECT_SOURCE | SUPPORT_VOLUME_MUTE
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def state(self):
"""Return the state of the device."""
return self._state
@property
def is_volume_muted(self):
#"""Boolean if volume is currently muted."""
return self._is_mute
@property
def volume_level(self):
"""Volume level of the media player (0..1)."""
return self._volume
@property
def source(self):
return self._source
#@property
#def source(self):
# return self._current_source
@property
def source_list(self):
return ['Sundeck', 'Owners Cabin', 'Loft', 'Bar', 'Winter Garden', 'Heli Hangar', 'Lazarette', 'DJ']
async def _connect_and_receive_data(self):
try:
self._is_subscribed = True
await self._event_loop.async_add_executor_job(subvolume, self._object_id, self._socket)
await self._event_loop.async_add_executor_job(subinput, self._zone_idL, self._socket)
await self._event_loop.async_add_executor_job(submeter, self._meter, self._socket)
await self._event_loop.async_add_executor_job(submute, self._object_id, self._socket)
#self._event_loop.create_task(self._receive_data())
except (ConnectionError, OSError) as ex:
_LOGGER.error("Error connecting to TCP device: %s", ex)
# Hier können Sie Fehler behandeln und den asynchronen Prozess beenden
async def _receive_data(self):
#print()
while self._is_subscribed:
response = await self._event_loop.async_add_executor_job(self._socket.recv, 1024)
if not response:
break
if(encodewithoutsubstitution(self._muteparameter)==decode(response)[8:10]):
if(encodewithoutsubstitution(self.object_id)==decode(response)[5:8]):
mute_state = bytetoint(decode(response)[10:11],decode(response)[11:14])
if(mute_state == 1):
mute_state = True
elif(mute_state == 0):
mute_state == False
self._is_mute = False
#self.async_write_ha_state()
else:
if(encodewithoutsubstitution(self._meter)==decode(response)[5:8]):
playing_state = (bytetoint(decode(response)[10:11],decode(response)[11:14])+800000)/10000
if(playing_state>15):
playing_state = STATE_PLAYING
else:
playing_state = STATE_IDLE
self._state = playing_state
#self.async_write_ha_state()
if(encodewithoutsubstitution(self._zone_idL)==decode(response)[5:8]):
input_source = bytetoint(decode(response)[10:11],decode(response)[11:14])
if(input_source==1):
input_source = "Sundeck"
if(input_source==2):
input_source = "Owners Cabin"
if(input_source==3):
input_source = "Loft"
if(input_source==4):
input_source = "Bar"
if(input_source==6):
input_source = "Winter Garden"
if(input_source==5):
input_source = "Heli Hangar"
if(input_source==7):
input_source = "Lazarette"
if(input_source==8):
input_source = "DJ"
self._source = input_source
#self.async_write_ha_state()
if(encodewithoutsubstitution(self._object_id)==decode(response)[5:8]):
volume = getvolumepercent(response)
self._volume = volume/100
self.async_write_ha_state()
async def async_will_remove_from_hass(self):
await super().async_will_remove_from_hass()
# Beenden Sie den asynchronen Prozess und räumen Sie auf
await self._unsubscribe_and_disconnect()
if self._data_receiver_task:
self._data_receiver_task.cancel()
await self._data_receiver_task
async def _unsubscribe_and_disconnect(self):
if self._is_subscribed:
self._is_subscribed = False
if self._socket:
self._socket.close()
self._socket = None
async def update_everything(self):
self._source = await self._event_loop.async_add_executor_job(subinput,self._zone_idL,self._socket)
self._volume = await self._event_loop.async_add_executor_job(subvolume,self._object_id,self._socket)
self._is_mute = await self._event_loop.async_add_executor_job(submute,self._object_id,self._socket)
self._state = await self._event_loop.async_add_executor_job(submeter,self._meter,self._socket)
"""async def async_update(self):
#print("hallo")
try:
self._socket.sendall(b'\x00')
except:
# recreate the socket and reconnect
_LOGGER.error("Reconnecting")
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.connect((ip_address, port))
return
#self._event_loop.create_task(self.update_everything())
#self._source = self._source
#self._source = subinput(self._zone_idL,self._socket)
#self._volume = subvolume(self._object_id,self._socket)/100
#self._is_mute = submute(self._object_id,self._socket)"""
async def async_added_to_hass(self):
await super().async_added_to_hass()
self._loop = asyncio.get_event_loop()
self._client_socket = None
self._is_subscribed = False
# Starten Sie den asynchronen Prozess zum Verbinden und Empfangen von Daten
await self._connect_and_receive_data()
async def async_volume_up(self):
bumpprecentpacket(self._object_id,5,False,self._socket)
self._volume += 0.05
async def async_volume_down(self):
bumpprecentpacket(self._object_id,5,True,self._socket)
self._volume -= 0.05
async def async_set_volume_level(self, volume):
self._volume = volume
setprecentpacket(self._object_id,(int)(volume*100),self._socket)
async def async_mute_volume(self, mute):
self._is_mute = mute
setmute(self._object_id,mute,self._socket)
#self._lara.volume_mute()
async def async_select_source(self, source):
self._source = source
if(source=="Sundeck"):
setsource(self._zone_idL,1,self._socket)
setsource(self._zone_idR,1,self._socket)
if(source=="Owners Cabin"):
setsource(self._zone_idL,2,self._socket)
setsource(self._zone_idR,2,self._socket)
if(source=="Loft"):
setsource(self._zone_idL,3,self._socket)
setsource(self._zone_idR,3,self._socket)
if(source=="Bar"):
setsource(self._zone_idL,4,self._socket)
setsource(self._zone_idR,4,self._socket)
if(source=="Winter Garden"):
setsource(self._zone_idL,6,self._socket)
setsource(self._zone_idR,6,self._socket)
if(source=="Heli Hangar"):
setsource(self._zone_idL,5,self._socket)
setsource(self._zone_idR,5,self._socket)
if(source=="Lazarette"):
setsource(self._zone_idL,7,self._socket)
setsource(self._zone_idR,7,self._socket)
if(source=="DJ"):
setsource(self._zone_idL,8,self._socket)
setsource(self._zone_idR,8,self._socket)
Can someone please help me.