Added server assisted roaming capability

This commit is contained in:
Pünkösd Marcell 2021-12-11 01:07:04 +01:00
parent e609411897
commit 46503b5d45
2 changed files with 104 additions and 7 deletions

View File

@ -5,8 +5,9 @@ import logging
from datetime import datetime from datetime import datetime
import requests import requests
from .abcsender import AbcSender from .abcsender import AbcSender
from utils import config from utils import config, LoopingTimer
from urllib.parse import urljoin from urllib.parse import urljoin
import time
""" """
Send a sound sample Send a sound sample
@ -23,6 +24,87 @@ class SoundSender(AbcSender):
SoundSender class, responsible for sending sound samples to the cloud. SoundSender class, responsible for sending sound samples to the cloud.
""" """
def __init__(self):
self._feed_url = None
self._reassign_timer = None
if not config.NO_AUTODISCOVER:
retry = 0
timeout = 30
while True:
try:
r = requests.post(
urljoin(config.API_URL, "/assignment"),
json={"device_id": config.DEVICE_ID},
timeout=timeout
)
except requests.exceptions.Timeout:
logging.warning(f"/assignment timed out after {timeout} sec! Retrying...")
continue
if r.status_code not in [200, 404]:
logging.warning(
f"Unexpected status code while acquiring an assignment: {r.status_code}. Retrying..."
)
time.sleep(5)
continue
if r.status_code == 404:
logging.info(
"/assignment returned 404 error. Assuming missing capability... Defaulting to use API_URL"
)
self._feed_url = config.API_URL
break
if r.json()['hard_default']:
retry += 1
if retry < 10:
logging.info(f"Still waiting for non hard-default url... Attempt {retry}/10")
time.sleep(6)
continue
else:
logging.info(f"Given up waiting for non hard-default url... accepting hard default.")
logging.info(f"Assigned to {r.json()['site']}")
self._feed_url = r.json()['url']
break
self._reassign_timer = LoopingTimer(config.REASSIGN_INTERVAL, lambda: self.reassign())
self._reassign_timer.start()
# If the above block failed to assign a feed_url
if not self._feed_url:
logging.info("Using API_URL as feed url")
self._feed_url = config.API_URL
def reassign(self):
logging.debug("Asking for reassign...")
timeout = 30
try:
r = requests.post(
urljoin(config.API_URL, "/assignment"),
json={"device_id": config.DEVICE_ID},
timeout=timeout
)
except requests.exceptions.Timeout:
logging.warning(f"/assignment timed out after {timeout} sec! Ignoring...")
return
if r.status_code == 404:
logging.debug("/assignment returned 404 status code. Assuming missing capability, and doing nothing...")
return
if r.status_code != 200:
logging.debug(f"/assignment returned {r.status_code} status code. Ignoring...")
return
logging.debug(f"Received assignment to {r.json()['site']}")
if r.json()['url'] != self._feed_url:
logging.info(f"Reassigned to {r.json()['site']}!")
# Because of GIL and because this is a reference, we don't really have to be careful assigning this
self._feed_url = r.json()['url']
def sendvalue(self, value: str, decision: bool) -> None: def sendvalue(self, value: str, decision: bool) -> None:
""" """
Send a sound sample to the cloud. Send a sound sample to the cloud.
@ -32,14 +114,24 @@ class SoundSender(AbcSender):
""" """
if decision: if decision:
files = { files = {
"file": (os.path.basename(value), open(value, 'rb').read(), 'audio/wave', "file": (
{'Content-length': os.path.getsize(value)}), os.path.basename(value),
open(value, 'rb').read(),
'audio/wave',
{'Content-length': os.path.getsize(value)}
),
"description": ( "description": (
None, json.dumps({'date': datetime.now().isoformat(), 'device_id': config.DEVICE_ID}), None,
"application/json") json.dumps({'date': datetime.now().isoformat(), 'device_id': config.DEVICE_ID}),
"application/json"
)
} }
r = requests.post(urljoin(config.API_URL, config.FEED_TYPE), files=files) r = requests.post(urljoin(self._feed_url, config.FEED_TYPE), files=files)
logging.debug(f"Content: {r.content.decode()}") logging.debug(f"Content: {r.content.decode()}")
logging.debug(f"Headers: {r.headers}") logging.debug(f"Headers: {r.headers}")
r.raise_for_status() r.raise_for_status()
def __del__(self):
if self._reassign_timer:
self._reassign_timer.stop()

View File

@ -37,7 +37,12 @@ DISABLE_AI = os.environ.get("DISABLE_AI", 'no').lower() in ['yes', '1', 'true']
PLATFORM = os.environ.get("PLATFORM", "raspberry") PLATFORM = os.environ.get("PLATFORM", "raspberry")
FEED_TYPE = os.environ.get("FEED_TYPE", "input") # probably the worst naming the type of the accepting service. FEED_TYPE = os.environ.get("FEED_TYPE", "input") # probably the worst naming the type of the accepting service.
if FEED_TYPE not in ['input', 'filter']: if FEED_TYPE not in ['input', 'filter']:
raise ValueError("FEED_TYPE must be either input or filter") raise ValueError("FEED_TYPE must be either input or filter")
# Skip fetching /assignment endpoint
NO_AUTODISCOVER = os.environ.get("NO_AUTODISCOVER", 'no').lower() in ['yes', '1', 'true']
REASSIGN_INTERVAL = int(os.environ.get("REASSIGN_INTERVAL", 120))