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

Commit

Permalink
Merge pull request #32 from nalabelle/webhook-delay-each-tilt
Browse files Browse the repository at this point in the history
store webhook delays per mac address (hopefully per tilt)
  • Loading branch information
myoung34 authored Oct 27, 2020
2 parents 711b4be + 22d60f5 commit 066acf6
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 31 deletions.
69 changes: 55 additions & 14 deletions tests/test_webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def test_webhook_get(
'gravity': 1,
'temp': 32,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558888
'timestamp': 155558888,
'uuid': 'a495bb30c5b14b44b5121370f02d74de'
})
assert mock_requests.mock_calls == [
mock.call.get('GET'),
Expand All @@ -53,7 +54,8 @@ def test_webhook_post_json(
'gravity': 1,
'temp': 32,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558888
'timestamp': 155558888,
'uuid': 'a495bb30c5b14b44b5121370f02d74de'
})
assert mock_requests.mock_calls == [
mock.call.get('POST'),
Expand Down Expand Up @@ -81,7 +83,8 @@ def test_webhook_post_data(
'gravity': 1,
'temp': 32,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558888
'timestamp': 155558888,
'uuid': 'a495bb30c5b14b44b5121370f02d74de'
})
assert mock_requests.mock_calls == [
mock.call.get('POST'),
Expand All @@ -108,7 +111,8 @@ def test_webhook_invalid_method():
'gravity': 1,
'temp': 32,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558888
'timestamp': 155558888,
'uuid': 'a495bb30c5b14b44b5121370f02d74de'
})


Expand All @@ -123,29 +127,35 @@ def test_webhook_delay_minutes(
'payload_template': '{"color": "{{ color }}", "gravity": {{ gravity }}, "temp": {{ temp }}}', # noqa
'method': 'GET',
}


wh = webhook.Webhook(config=config)
# On init, we load delay_minutes from config
assert wh.delay_minutes == 3
# delay_until is unset until emitting calling emit once
assert wh.delay_until is None
delay_until = wh.delay_until.get('black')
assert delay_until is None
wh.emit({
'color': 'black',
'gravity': 1,
'temp': 32,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558888
'temp': 32,
'timestamp': 155558888,
'uuid': 'a495bb30c5b14b44b5121370f02d74de',
})
wh.emit({
'color': 'black',
'gravity': 2,
'temp': 33,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558899
'temp': 33,
'timestamp': 155558899,
'uuid': 'a495bb30c5b14b44b5121370f02d74de',
})
now = datetime.datetime.now(datetime.timezone.utc)
assert wh.delay_minutes == 3
# delay_until should be set for about 3 minutes from now
assert wh.delay_until is not None and wh.delay_until >= now
delay_until = wh.delay_until.get(black_tilt_uuid)
assert delay_until is not None and delay_until >= now
# emitted twice, but the second returned before actually sending a request.
assert mock_requests.mock_calls == [
mock.call.get('GET'),
Expand All @@ -155,18 +165,45 @@ def test_webhook_delay_minutes(
json={'color': 'black', 'gravity': 1, 'temp': 32}, url='http://example.com') # noqa
]

# enxure that the blue tilt can send while the black one is waiting
delay_until = wh.delay_until.get(blue_tilt_uuid)
assert delay_until is None
wh.emit({
'color': 'blue',
'gravity': 99,
'mac': '00:0a:95:9d:68:17',
'temp': 99,
'timestamp': 155559999,
'uuid': blue_tilt_uuid
})
delay_until = wh.delay_until.get(blue_tilt_uuid)
assert delay_until is not None and delay_until >= now
assert mock_requests.mock_calls == [
mock.call.get('GET'),
mock.ANY,
mock.call.get()(
headers={'Content-Type': 'application/json'},
json={'color': 'black', 'gravity': 1, 'temp': 32}, url='http://example.com'), # noqa
mock.ANY,
mock.call.get()(
headers={'Content-Type': 'application/json'},
json={'color': 'blue', 'gravity': 99, 'temp': 99}, url='http://example.com') # noqa
]

# move the clock forward by setting delay_until to the past, which should
# allow a request to process again
wh.delay_until = now - datetime.timedelta(minutes=1)
wh.delay_until[black_tilt_uuid] = now - datetime.timedelta(minutes=1)
wh.emit({
'color': 'black',
'gravity': 3,
'temp': 34,
'mac': '00:0a:95:9d:68:16',
'timestamp': 155558899
'temp': 34,
'timestamp': 155558899,
'uuid': black_tilt_uuid
})
# delay_until is once again about 3 minutes in the future
assert wh.delay_until is not None and wh.delay_until >= now
delay_until = wh.delay_until.get(black_tilt_uuid)
assert delay_until is not None and delay_until >= now
# we now see the request that was made after the delay timeout
assert mock_requests.mock_calls == [
mock.call.get('GET'),
Expand All @@ -175,6 +212,10 @@ def test_webhook_delay_minutes(
headers={'Content-Type': 'application/json'},
json={'color': 'black', 'gravity': 1, 'temp': 32}, url='http://example.com'), # noqa
mock.ANY,
mock.call.get()(
headers={'Content-Type': 'application/json'},
json={'color': 'blue', 'gravity': 99, 'temp': 99}, url='http://example.com'), # noqa
mock.ANY,
mock.call.get()(
headers={'Content-Type': 'application/json'},
json={'color': 'black', 'gravity': 3, 'temp': 34}, url='http://example.com') # noqa
Expand Down
7 changes: 4 additions & 3 deletions tilty/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ def scan_and_emit(device: tilt_device.TiltDevice, emitters: List[dict]):
LOGGER.debug('Starting device scan')
tilt_data = device.scan_for_tilt_data()
if tilt_data:
LOGGER.debug('tilt data retrieved')
LOGGER.info(tilt_data)
emit(emitters=emitters, tilt_data=tilt_data)
for event in tilt_data:
LOGGER.debug('tilt data retrieved')
LOGGER.info(event)
emit(emitters=emitters, tilt_data=event)
else:
LOGGER.debug('No tilt data')

Expand Down
19 changes: 12 additions & 7 deletions tilty/emitters/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,23 @@ def __init__(self, config: dict) -> None:
self.delay_minutes: Union[int, None] = delay_minutes
self.headers: dict = json.loads(config['headers'])
self.template: Template = Template(config['payload_template'])
self.delay_until: Union[datetime.datetime, None] = None
self.delay_until_identifier = config.get(
'delay_until_identifier',
'color'
)

def emit(self, tilt_data: dict) -> None: # pylint:disable=inconsistent-return-statements # noqa
def emit(self, tilt_data: dict) -> None:
""" Initializer
Args:
tilt_data (dict): data returned from valid tilt device scan
"""

delay_until_identifier = str(tilt_data[self.delay_until_identifier])
now = datetime.datetime.now(datetime.timezone.utc)
if self.delay_until and now < self.delay_until:
return
delay_until = self.delay_until.get(delay_until_identifier)
if delay_until and now < delay_until:
return None

payload: dict = json.loads(self.template.render(
color=tilt_data['color'],
Expand All @@ -72,8 +77,8 @@ def emit(self, tilt_data: dict) -> None: # pylint:disable=inconsistent-return-s
)

if self.delay_minutes:
self.delay_until = now + datetime.timedelta(
minutes=self.delay_minutes)
timedelta = datetime.timedelta(minutes=self.delay_minutes)
self.delay_until[delay_until_identifier] = now + timedelta

if self.headers and 'json' in self.headers.get('Content-Type', {}):
LOGGER.debug('[webhook] sending as json')
Expand All @@ -89,4 +94,4 @@ def emit(self, tilt_data: dict) -> None: # pylint:disable=inconsistent-return-s
data=payload,
)
response.raise_for_status()
return
return None
19 changes: 12 additions & 7 deletions tilty/tilt_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,29 @@ def stop(self) -> None:
LOGGER.debug('Stopping device socket')
blescan.hci_disable_le_scan(self.sock)

def scan_for_tilt_data(self) -> dict:
def scan_for_tilt_data(self) -> list:
""" scan for tilt and return data if found """

data = {}
data = []
LOGGER.debug('Looking for events')
for beacon in blescan.get_events(self.sock):
if beacon['uuid'] in constants.TILT_DEVICES:
data = {
'color': constants.TILT_DEVICES[beacon['uuid']],
uuid = beacon.get('uuid')
if uuid is None:
continue
color = constants.TILT_DEVICES.get(uuid)
if color:
data.append({
'color': color,
'gravity': float(beacon['minor']/1000),
'temp': beacon['major'],
'mac': beacon['mac'],
'timestamp': datetime.now().isoformat(),
}
'uuid': uuid
})
else:
LOGGER.debug(
"Beacon UUID is not a tilt device: %s",
beacon['uuid']
uuid
)

return data

0 comments on commit 066acf6

Please sign in to comment.