Added server assisted roaming capability
This commit is contained in:
parent
e609411897
commit
46503b5d45
@ -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()
|
||||||
|
@ -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))
|
||||||
|
Loading…
Reference in New Issue
Block a user