zapsaber/pyshock.py

98 lines
3.2 KiB
Python
Executable File

from enum import Enum
import json
import logging
import requests
logger = logging.getLogger(__name__)
class PiShock:
"""
PiShock represents a connection to the PiShock API. See https://pishock.com
for the spec. It also allows a maximum duration and intensity to be set regardless
of the share code's limitations.
"""
PISHOCK_API = 'https://do.pishock.com/api/apioperate/'
NAME = 'PyShock'
ACTIONS = Enum('ACTIONS', ['shock', 'vibrate', 'beep'])
def __init__(self, username: str, api_key: str, code: str, name: str = '',
max_intensity: int = 50, max_duration: int = 5):
self.username = username
self.api_key = api_key
self.code = code
self.name = name if name else self.NAME
self.max_intensity = max_intensity
self.max_duration = max_duration
def shock(self, duration: int = 1, intensity: int = 5):
"""
shock sends a shock command with the given duration and intensity.
"""
self._act(self.ACTIONS.shock, duration, intensity)
def vibrate(self, duration: int = 1, intensity: int = 5):
"""
vibrate sends a vibrate command with the given duration and intensity.
"""
self._act(self.ACTIONS.vibrate, duration, intensity)
def beep(self, duration: int = 1):
"""
beep sends a beep command with the given duration.
"""
self._act(self.ACTIONS.beep, duration)
def act(self, op_readable: str, duration: int, intensity: int):
"""
act accepts a readable operation ('shock', 'vibrate', or 'beep') and the
required duration/intensity parameters as might be specified in a config
file, and fires the appropriate event.
"""
try:
self._act(self.ACTIONS[op_readable], duration, intensity)
except AttributeError as e:
logger.warning('Action not found: {}', e)
def _act(self, op: str, duration: int = 1, intensity: int = 5):
"""
_act fires the actual event by posting to the PiShock API.
"""
# Ensure we're not violating local maximums.
if duration > self.max_duration:
logger.error('%d is greater than maximum allowed duration, %d',
duration, self.max_duration)
return
if intensity > self.max_intensity:
logger.error('%d is greater than maximum allowed intensity, %d',
intensity, self.max_intensity)
return
# Build the request object.
req = {
'Username': self.username,
'Apikey': self.api_key,
'Code': self.code,
'Name': self.name,
'Op': str(op.value - 1),
'Duration': duration
}
if op in [self.ACTIONS.shock, self.ACTIONS.vibrate]:
req['Intensity'] = intensity
# Send the request. If it didn't succeed, log a warning.
logger.debug(req)
res = requests.post(self.PISHOCK_API,
json=req, headers={'Content-Type': 'application/json'})
logger.debug(res.text)
if res.status_code != 200 or res.text != 'Operation Succeeded.':
logger.warning('Error communicating with shocker: %s', res.text)