Skip to content
This repository has been archived by the owner on Dec 12, 2023. It is now read-only.

Group distribution to enable JOIN/UNJOIN services in Homeassistant #13

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
44 changes: 30 additions & 14 deletions pymusiccast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class McDevice(object):
"""docstring for McDevice"""
def __init__(self, ip_address, udp_port=5005, **kwargs):
super(McDevice, self).__init__()
_LOGGER.debug("McDevice: %s", ip_address)
_LOGGER.debug("%s: New McDevice", ip_address)
# construct message queue
self.messages = queue.Queue()
self._ip_address = ip_address
Expand All @@ -36,6 +36,7 @@ def __init__(self, ip_address, udp_port=5005, **kwargs):
self.device_features = None
self.location_info = None
self.network_status = None
self.distribution_info = None
self.update_status_timer = None
try:
self.initialize()
Expand Down Expand Up @@ -73,10 +74,10 @@ def healthy_update_timer(self):
state = None

if self.update_status_timer and self.update_status_timer.is_alive():
_LOGGER.debug("Timer: healthy")
_LOGGER.debug("%s: Timer: healthy", self._ip_address)
state = True
else:
_LOGGER.debug("Timer: not healthy")
_LOGGER.debug("%s: Timer: not healthy", self._ip_address)
state = False

return state
Expand All @@ -93,11 +94,12 @@ def initialize(self):
self.initialize_socket()
self.initialize_worker()
self.initialize_zones()
self.update_distribution_info()

def initialize_socket(self):
"""initialize the socket"""
try:
_LOGGER.debug("Trying to open socket.")
_LOGGER.debug("%s: Trying to open socket.", self._ip_address)
self._socket = socket.socket(
socket.AF_INET, # IPv4
socket.SOCK_DGRAM # UDP
Expand All @@ -106,7 +108,7 @@ def initialize_socket(self):
except socket.error as err:
raise err
else:
_LOGGER.debug("Socket open.")
_LOGGER.debug("%s: Socket open.", self._ip_address)
socket_thread = threading.Thread(
name="SocketThread", target=socket_worker,
args=(self._socket, self.messages,))
Expand All @@ -128,7 +130,7 @@ def initialize_zones(self):
if zone_list[zone_id]: # Location setup is valid
self.zones[zone_id] = Zone(self, zone_id=zone_id)
else: # Location setup is not valid
_LOGGER.debug("Ignoring zone: %s", zone_id)
_LOGGER.debug("%s: Ignoring zone: %s", self._ip_address, zone_id)

def get_device_info(self):
"""Get info from device"""
Expand Down Expand Up @@ -162,7 +164,7 @@ def get_status(self):
def handle_status(self):
"""Handle status from device"""
status = self.get_status()

_LOGGER.debug("%s: getting status.", self._ip_address)
if status:
# Update main-zone
self.zones['main'].update_status(status)
Expand Down Expand Up @@ -196,7 +198,7 @@ def handle_netusb(self, message):
new_status = STATE_UNKNOWN

if self._yamaha.status is not new_status:
_LOGGER.debug("playback: %s", new_status)
_LOGGER.debug("%s: playback: %s", self._ip_address, new_status)
self._yamaha.status = new_status
needs_update += 1

Expand All @@ -211,25 +213,39 @@ def handle_features(self, device_features):
for zone in device_features['zone']:
zone_id = zone.get('id')
if zone_id in self.zones:
_LOGGER.debug("handle_features: %s", zone_id)
_LOGGER.debug("%s: handle_features: %s", self._ip_address, zone_id)
input_list = zone.get('input_list', [])
input_list.sort()
self.zones[zone_id].source_list = input_list

def update_distribution_info(self):
"""Get distribution info from device and update zone"""
req_url = ENDPOINTS["getDistributionInfo"].format(self._ip_address)
response = request(req_url)
_LOGGER.debug("%s: Distribution Info Message: %s", self._ip_address, response)
if 'server_zone' in response:
server_zone = response.get('server_zone')
self.zones[server_zone].update_distribution_info(response)
else:
self.zones['main'].update_distribution_info(response)

def handle_event(self, message):
"""Dispatch all event messages"""
# _LOGGER.debug(message)
needs_update = 0
for zone in self.zones:
if zone in message:
_LOGGER.debug("Received message for zone: %s", zone)
_LOGGER.debug("%s: Received message for zone: %s", self._ip_address, zone)
self.zones[zone].update_status(message[zone])

if 'netusb' in message:
needs_update += self.handle_netusb(message['netusb'])

if 'dist' in message:
self.update_distribution_info()

if needs_update > 0:
_LOGGER.debug("needs_update: %d", needs_update)
_LOGGER.debug("%s: needs_update: %d", self._ip_address, needs_update)
self.update_hass()

def update_hass(self):
Expand All @@ -253,15 +269,15 @@ def update_status(self, reset=False):

def setup_update_timer(self, reset=False):
"""Schedule a Timer Thread."""
_LOGGER.debug("Timer: firing again in %d seconds", self._interval)
_LOGGER.debug("%s: Timer: firing again in %d seconds", self._ip_address, self._interval)
self.update_status_timer = threading.Timer(
self._interval, self.update_status, [True])
self.update_status_timer.setDaemon(True)
self.update_status_timer.start()

def set_yamaha_device(self, yamaha_device):
"""Set reference to device in HASS"""
_LOGGER.debug("setYamahaDevice: %s", yamaha_device)
_LOGGER.debug("%s: setYamahaDevice: %s", self._ip_address, yamaha_device)
self._yamaha = yamaha_device

def get_play_info(self):
Expand All @@ -277,5 +293,5 @@ def set_playback(self, playback):

def __del__(self):
if self._socket:
_LOGGER.debug("Closing Socket.")
_LOGGER.debug("%s: Closing Socket.", self._ip_address)
self._socket.close()
9 changes: 9 additions & 0 deletions pymusiccast/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
"setMute": "http://{}/YamahaExtendedControl/v1/{}/setMute",
"setPower": "http://{}/YamahaExtendedControl/v1/{}/setPower",
"setVolume": "http://{}/YamahaExtendedControl/v1/{}/setVolume",
"getDistributionInfo": "http://{}/YamahaExtendedControl"
"/v1/dist/getDistributionInfo",
"setServerInfo": "http://{}/YamahaExtendedControl/v1/dist/setServerInfo",
"setClientInfo": "http://{}/YamahaExtendedControl/v1/dist/setClientInfo",
"startDistribution": "http://{}/YamahaExtendedControl"
"/v1/dist/startDistribution",
"stopDistribution": "http://{}/YamahaExtendedControl"
"/v1/dist/stopDistribution",
"setGroupName": "http://{}/YamahaExtendedControl/v1/dist/setGroupName",
}

STATE_UNKNOWN = "unknown"
Expand Down
11 changes: 6 additions & 5 deletions pymusiccast/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
import time
import logging
import requests
import re
_LOGGER = logging.getLogger(__name__)


def request(url, *args, **kwargs):
"""Do the HTTP Request and return data"""
method = kwargs.get('method', 'GET')
method = kwargs.pop('method', 'GET')
timeout = kwargs.pop('timeout', 10) # hass default timeout
req = requests.request(method, url, *args, timeout=timeout, **kwargs)
data = req.json()
_LOGGER.debug(json.dumps(data))
ip = re.findall(r'[0-9]+(?:\.[0-9]+){3}', url)
hcoohb marked this conversation as resolved.
Show resolved Hide resolved
_LOGGER.debug("%s: " + json.dumps(data), ip[0])
return data


Expand All @@ -38,9 +40,8 @@ def message_worker(device):
if device_id == device.device_id:
device.handle_event(data)
else:
_LOGGER.warning("Received message for unknown device.")
_LOGGER.warning("%s: Received message for unknown device.", device._ip_address)
msg_q.task_done()

time.sleep(0.2)


Expand All @@ -53,6 +54,6 @@ def socket_worker(sock, msg_q):
except OSError as err:
_LOGGER.error(err)
else:
_LOGGER.debug("received message: %s from %s", data, addr)
_LOGGER.debug("%s received message: %s from %s", addr, data, addr)
msg_q.put(data)
time.sleep(0.2)
Loading