forked from platypush/platypush
Implemented local backend
This commit is contained in:
parent
3b74ed2bb7
commit
e9e0512a52
5 changed files with 91 additions and 6 deletions
17
README.md
17
README.md
|
@ -17,9 +17,22 @@ Copy /etc/runbullet/config.example.yaml to /etc/runbullet/config.yaml (system-wi
|
||||||
|
|
||||||
Edit the file to include:
|
Edit the file to include:
|
||||||
|
|
||||||
|
### For the PushBullet backend
|
||||||
|
|
||||||
* Your PushBullet access token (create one [here](https://www.pushbullet.com/#settings/account));
|
* Your PushBullet access token (create one [here](https://www.pushbullet.com/#settings/account));
|
||||||
* The name of the (virtual) PushBullet device used to listen for events (create one [here](https://www.pushbullet.com/#devices)).
|
* The name of the (virtual) PushBullet device used to listen for events (create one [here](https://www.pushbullet.com/#devices)).
|
||||||
|
|
||||||
|
### For the Apache Kafka backend
|
||||||
|
|
||||||
|
* The host and port of the Kafka installation
|
||||||
|
* The topic that will be used to deliver and process messages
|
||||||
|
|
||||||
|
### For the local socket backend
|
||||||
|
|
||||||
|
* The name of the local FIFO that will be used to deliver and process messages
|
||||||
|
|
||||||
|
### device_id
|
||||||
|
|
||||||
Each target device is identified by a unique device_id in the messages sent over your account. The device_id is the hostname by default, unless changed in config.yaml.
|
Each target device is identified by a unique device_id in the messages sent over your account. The device_id is the hostname by default, unless changed in config.yaml.
|
||||||
|
|
||||||
Shell interface
|
Shell interface
|
||||||
|
@ -65,10 +78,10 @@ music.mpd:
|
||||||
pusher --target raspberry --action switch.wemo.on
|
pusher --target raspberry --action switch.wemo.on
|
||||||
```
|
```
|
||||||
|
|
||||||
* *TODO* `runbullet.plugins.light.hue`: Controls a Philips Hue smart lights system. Requires the package `phue` on the target machine. Example:
|
* `runbullet.plugins.light.hue`: Controls a Philips Hue smart lights system. Requires the package `phue` on the target machine. Example:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pusher --target raspberry --action light.hue.set_scene --scene "Sunset" --group "Living Room"
|
pusher --target raspberry --action light.hue.scene --name "Sunset" --group "Living Room"
|
||||||
```
|
```
|
||||||
|
|
||||||
Writing your plugins
|
Writing your plugins
|
||||||
|
|
|
@ -39,12 +39,16 @@ class Backend(Thread):
|
||||||
if cls is not object and hasattr(cls, '_init'):
|
if cls is not object and hasattr(cls, '_init'):
|
||||||
cls._init(self, **config)
|
cls._init(self, **config)
|
||||||
|
|
||||||
|
def is_local(self):
|
||||||
|
from runbullet.backend.local import LocalBackend
|
||||||
|
return isinstance(self, LocalBackend)
|
||||||
|
|
||||||
def on_msg(self, msg):
|
def on_msg(self, msg):
|
||||||
if 'target' not in msg:
|
if 'target' not in msg:
|
||||||
return # No target
|
return # No target
|
||||||
|
|
||||||
target = msg.pop('target')
|
target = msg.pop('target')
|
||||||
if target != runbullet.get_device_id():
|
if target != runbullet.get_device_id() and not self.is_local():
|
||||||
return # Not for me
|
return # Not for me
|
||||||
|
|
||||||
if 'action' not in msg:
|
if 'action' not in msg:
|
||||||
|
|
49
runbullet/backend/local/__init__.py
Normal file
49
runbullet/backend/local/__init__.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from .. import Backend
|
||||||
|
|
||||||
|
class LocalBackend(Backend):
|
||||||
|
def _init(self, fifo):
|
||||||
|
self.fifo = fifo
|
||||||
|
try: os.mkfifo(self.fifo)
|
||||||
|
except FileExistsError as e: pass
|
||||||
|
logging.info('Initialized local backend on fifo {}'.format(self.fifo))
|
||||||
|
|
||||||
|
def send_msg(self, msg):
|
||||||
|
if isinstance(msg, dict):
|
||||||
|
msg = json.dumps(msg)
|
||||||
|
if not isinstance(msg, str):
|
||||||
|
msg = json.dumps(msg)
|
||||||
|
raise RuntimeError('Invalid non-JSON message')
|
||||||
|
|
||||||
|
msglen = len(msg)+1 # Include \n
|
||||||
|
msg = bytearray((str(msglen) + '\n' + msg + '\n').encode('utf-8'))
|
||||||
|
with open(self.fifo, 'wb') as f:
|
||||||
|
f.write(msg)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
with open(self.fifo, 'rb', 0) as f:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
msglen = int(f.readline())
|
||||||
|
except ValueError as e:
|
||||||
|
time.sleep(0.1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
msg = f.read(msglen-1)
|
||||||
|
if not msg: continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
msg = json.loads(msg.decode('utf-8'))
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
continue
|
||||||
|
|
||||||
|
logging.debug('Received message: {}'.format(msg))
|
||||||
|
self.on_msg(msg)
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -10,6 +10,7 @@ import yaml
|
||||||
from pushbullet import Pushbullet
|
from pushbullet import Pushbullet
|
||||||
from runbullet import parse_config_file
|
from runbullet import parse_config_file
|
||||||
from runbullet.backend.kafka import KafkaBackend
|
from runbullet.backend.kafka import KafkaBackend
|
||||||
|
from runbullet.backend.local import LocalBackend
|
||||||
|
|
||||||
|
|
||||||
def print_usage():
|
def print_usage():
|
||||||
|
@ -40,10 +41,18 @@ def send_pb_message(pb, device_name, msg):
|
||||||
def send_kafka_message(backend, msg):
|
def send_kafka_message(backend, msg):
|
||||||
backend.send_msg(msg)
|
backend.send_msg(msg)
|
||||||
|
|
||||||
|
def send_local_message(backend, msg):
|
||||||
|
backend.send_msg(msg)
|
||||||
|
|
||||||
def get_backend(config):
|
def get_backend(config):
|
||||||
# TODO Refactor this as something better and reuse the same
|
# TODO Refactor this as something better and reuse the same
|
||||||
# backend classes from the runbullet consumer module
|
# backend classes from the runbullet consumer module
|
||||||
if 'backend.pushbullet' in config \
|
if 'backend.local' in config \
|
||||||
|
and 'pusher' in config['backend.local'] \
|
||||||
|
and config['backend.local']['pusher']:
|
||||||
|
c = config['backend.local']
|
||||||
|
return LocalBackend({'fifo': c['fifo']})
|
||||||
|
elif 'backend.pushbullet' in config \
|
||||||
and 'pusher' in config['backend.pushbullet'] \
|
and 'pusher' in config['backend.pushbullet'] \
|
||||||
and config['backend.pushbullet']['pusher']:
|
and config['backend.pushbullet']['pusher']:
|
||||||
API_KEY = config['backend.pushbullet']['token']
|
API_KEY = config['backend.pushbullet']['token']
|
||||||
|
@ -66,8 +75,8 @@ def main():
|
||||||
|
|
||||||
parser.add_argument('--backend', '-b', dest='backend', required=False,
|
parser.add_argument('--backend', '-b', dest='backend', required=False,
|
||||||
help="Backend to deliver the message " +
|
help="Backend to deliver the message " +
|
||||||
"[pushbullet|kafka] (default: whatever specified " +
|
"[pushbullet|kafka|local] (default: whatever " +
|
||||||
"in your config with pusher=True)")
|
"specified in your config with pusher=True)")
|
||||||
|
|
||||||
opts, args = parser.parse_known_args(sys.argv[1:])
|
opts, args = parser.parse_known_args(sys.argv[1:])
|
||||||
payload = {}
|
payload = {}
|
||||||
|
@ -76,6 +85,11 @@ def main():
|
||||||
raise RuntimeError('Odd number of key-value options passed: {}'.
|
raise RuntimeError('Odd number of key-value options passed: {}'.
|
||||||
format(args))
|
format(args))
|
||||||
|
|
||||||
|
if opts.target == 'localhost' and 'backend.local' in config:
|
||||||
|
cfg = config['backend.local']
|
||||||
|
cfg['pusher'] = True
|
||||||
|
config = { 'backend.local': cfg }
|
||||||
|
|
||||||
if opts.backend:
|
if opts.backend:
|
||||||
backend_cfg_name = 'backend.' + opts.backend
|
backend_cfg_name = 'backend.' + opts.backend
|
||||||
if backend_cfg_name not in config:
|
if backend_cfg_name not in config:
|
||||||
|
@ -103,6 +117,8 @@ def main():
|
||||||
send_pb_message(backend, config['backend.pushbullet']['device'], msg)
|
send_pb_message(backend, config['backend.pushbullet']['device'], msg)
|
||||||
elif isinstance(backend, KafkaBackend):
|
elif isinstance(backend, KafkaBackend):
|
||||||
send_kafka_message(backend, msg)
|
send_kafka_message(backend, msg)
|
||||||
|
elif isinstance(backend, LocalBackend):
|
||||||
|
send_local_message(backend, msg)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -11,6 +11,9 @@ backend.pushbullet:
|
||||||
token: your_pushbullet_token_here
|
token: your_pushbullet_token_here
|
||||||
device: your_pushbullet_virtual_device_name
|
device: your_pushbullet_virtual_device_name
|
||||||
|
|
||||||
|
backend.local:
|
||||||
|
fifo: /tmp/runbullet.fifo
|
||||||
|
|
||||||
# device_id: <your_device_id> (default: current hostname)
|
# device_id: <your_device_id> (default: current hostname)
|
||||||
# debug: True (default: False)
|
# debug: True (default: False)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue