Add MQTT notification agent

This commit is contained in:
JonnyWong16 2017-08-23 20:51:27 -07:00
commit aee752e04e
5 changed files with 2678 additions and 1 deletions

0
lib/paho/__init__.py Normal file
View file

View file

@ -0,0 +1 @@
__version__ = "1.1"

2337
lib/paho/mqtt/client.py Normal file

File diff suppressed because it is too large Load diff

217
lib/paho/mqtt/publish.py Normal file
View file

@ -0,0 +1,217 @@
# Copyright (c) 2014 Roger Light <roger@atchoo.org>
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# and Eclipse Distribution License v1.0 which accompany this distribution.
#
# The Eclipse Public License is available at
# http://www.eclipse.org/legal/epl-v10.html
# and the Eclipse Distribution License is available at
# http://www.eclipse.org/org/documents/edl-v10.php.
#
# Contributors:
# Roger Light - initial API and implementation
"""
This module provides some helper functions to allow straightforward publishing
of messages in a one-shot manner. In other words, they are useful for the
situation where you have a single/multiple messages you want to publish to a
broker, then disconnect and nothing else is required.
"""
import paho.mqtt.client as mqtt
def _do_publish(c):
"""Internal function"""
m = c._userdata[0]
c._userdata = c._userdata[1:]
if type(m) is dict:
topic = m['topic']
try:
payload = m['payload']
except KeyError:
payload = None
try:
qos = m['qos']
except KeyError:
qos = 0
try:
retain = m['retain']
except KeyError:
retain = False
elif type(m) is tuple:
(topic, payload, qos, retain) = m
else:
raise ValueError('message must be a dict or a tuple')
c.publish(topic, payload, qos, retain)
def _on_connect(c, userdata, flags, rc):
"""Internal callback"""
_do_publish(c)
def _on_publish(c, userdata, mid):
"""Internal callback"""
if len(userdata) == 0:
c.disconnect()
else:
_do_publish(c)
def multiple(msgs, hostname="localhost", port=1883, client_id="", keepalive=60,
will=None, auth=None, tls=None, protocol=mqtt.MQTTv31):
"""Publish multiple messages to a broker, then disconnect cleanly.
This function creates an MQTT client, connects to a broker and publishes a
list of messages. Once the messages have been delivered, it disconnects
cleanly from the broker.
msgs : a list of messages to publish. Each message is either a dict or a
tuple.
If a dict, only the topic must be present. Default values will be
used for any missing arguments. The dict must be of the form:
msg = {'topic':"<topic>", 'payload':"<payload>", 'qos':<qos>,
'retain':<retain>}
topic must be present and may not be empty.
If payload is "", None or not present then a zero length payload
will be published.
If qos is not present, the default of 0 is used.
If retain is not present, the default of False is used.
If a tuple, then it must be of the form:
("<topic>", "<payload>", qos, retain)
hostname : a string containing the address of the broker to connect to.
Defaults to localhost.
port : the port to connect to the broker on. Defaults to 1883.
client_id : the MQTT client id to use. If "" or None, the Paho library will
generate a client id automatically.
keepalive : the keepalive timeout value for the client. Defaults to 60
seconds.
will : a dict containing will parameters for the client: will = {'topic':
"<topic>", 'payload':"<payload">, 'qos':<qos>, 'retain':<retain>}.
Topic is required, all other parameters are optional and will
default to None, 0 and False respectively.
Defaults to None, which indicates no will should be used.
auth : a dict containing authentication parameters for the client:
auth = {'username':"<username>", 'password':"<password>"}
Username is required, password is optional and will default to None
if not provided.
Defaults to None, which indicates no authentication is to be used.
tls : a dict containing TLS configuration parameters for the client:
dict = {'ca_certs':"<ca_certs>", 'certfile':"<certfile>",
'keyfile':"<keyfile>", 'tls_version':"<tls_version>",
'ciphers':"<ciphers">}
ca_certs is required, all other parameters are optional and will
default to None if not provided, which results in the client using
the default behaviour - see the paho.mqtt.client documentation.
Defaults to None, which indicates that TLS should not be used.
"""
if type(msgs) is not list:
raise ValueError('msgs must be a list')
client = mqtt.Client(client_id=client_id,
userdata=msgs, protocol=protocol)
client.on_publish = _on_publish
client.on_connect = _on_connect
if auth is not None:
username = auth['username']
try:
password = auth['password']
except KeyError:
password = None
client.username_pw_set(username, password)
if will is not None:
will_topic = will['topic']
try:
will_payload = will['payload']
except KeyError:
will_payload = None
try:
will_qos = will['qos']
except KeyError:
will_qos = 0
try:
will_retain = will['retain']
except KeyError:
will_retain = False
client.will_set(will_topic, will_payload, will_qos, will_retain)
if tls is not None:
ca_certs = tls['ca_certs']
try:
certfile = tls['certfile']
except KeyError:
certfile = None
try:
keyfile = tls['keyfile']
except KeyError:
keyfile = None
try:
tls_version = tls['tls_version']
except KeyError:
tls_version = None
try:
ciphers = tls['ciphers']
except KeyError:
ciphers = None
client.tls_set(ca_certs, certfile, keyfile, tls_version=tls_version,
ciphers=ciphers)
client.connect(hostname, port, keepalive)
client.loop_forever()
def single(topic, payload=None, qos=0, retain=False, hostname="localhost",
port=1883, client_id="", keepalive=60, will=None, auth=None,
tls=None, protocol=mqtt.MQTTv31):
"""Publish a single message to a broker, then disconnect cleanly.
This function creates an MQTT client, connects to a broker and publishes a
single message. Once the message has been delivered, it disconnects cleanly
from the broker.
topic : the only required argument must be the topic string to which the
payload will be published.
payload : the payload to be published. If "" or None, a zero length payload
will be published.
qos : the qos to use when publishing, default to 0.
retain : set the message to be retained (True) or not (False).
hostname : a string containing the address of the broker to connect to.
Defaults to localhost.
port : the port to connect to the broker on. Defaults to 1883.
client_id : the MQTT client id to use. If "" or None, the Paho library will
generate a client id automatically.
keepalive : the keepalive timeout value for the client. Defaults to 60
seconds.
will : a dict containing will parameters for the client: will = {'topic':
"<topic>", 'payload':"<payload">, 'qos':<qos>, 'retain':<retain>}.
Topic is required, all other parameters are optional and will
default to None, 0 and False respectively.
Defaults to None, which indicates no will should be used.
auth : a dict containing authentication parameters for the client:
auth = {'username':"<username>", 'password':"<password>"}
Username is required, password is optional and will default to None
if not provided.
Defaults to None, which indicates no authentication is to be used.
tls : a dict containing TLS configuration parameters for the client:
dict = {'ca_certs':"<ca_certs>", 'certfile':"<certfile>",
'keyfile':"<keyfile>", 'tls_version':"<tls_version>",
'ciphers':"<ciphers">}
ca_certs is required, all other parameters are optional and will
default to None if not provided, which results in the client using
the default behaviour - see the paho.mqtt.client documentation.
Defaults to None, which indicates that TLS should not be used.
"""
msg = {'topic':topic, 'payload':payload, 'qos':qos, 'retain':retain}
multiple([msg], hostname, port, client_id, keepalive, will, auth, tls, protocol)

View file

@ -19,6 +19,7 @@ import json
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import email.utils
from paho.mqtt.publish import single
import os
import re
import requests
@ -84,7 +85,8 @@ AGENT_IDS = {'growl': 0,
'hipchat': 19,
'discord': 20,
'androidapp': 21,
'groupme': 22
'groupme': 22,
'mqtt': 23
}
@ -137,6 +139,10 @@ def available_notification_agents():
'name': 'nma',
'id': AGENT_IDS['nma']
},
{'label': 'MQTT',
'name': 'mqtt',
'id': AGENT_IDS['mqtt']
},
{'label': 'Plex Home Theater',
'name': 'plex',
'id': AGENT_IDS['plex']
@ -365,6 +371,8 @@ def get_agent_class(agent_id=None, config=None):
return ANDROIDAPP(config=config)
elif agent_id == 22:
return GROUPME(config=config)
elif agent_id == 23:
return MQTT(config=config)
else:
return Notifier(config=config)
else:
@ -2022,6 +2030,119 @@ class JOIN(Notifier):
return config_option
class MQTT(Notifier):
"""
MQTT notifications
"""
_DEFAULT_CONFIG = {'broker': '',
'port': 1883,
'protocol': 'MQTTv311',
'username': '',
'password': '',
'client_id': 'plexpy',
'topic': '',
'qos': 1,
'retain': 0,
'keep_alive': 60
}
def notify(self, subject='', body='', action='', **kwargs):
if not subject or not body:
return
if not self.config['topic']:
logger.error(u"PlexPy Notifiers :: MQTT topic not specified.")
return
data = {'subject': subject.encode("utf-8"),
'body': body.encode("utf-8"),
'topic': self.config['topic'].encode("utf-8")}
auth = {}
if self.config['username']:
auth['username'] = self.config['username']
if self.config['password']:
auth['password'] = self.config['password']
single(self.config['topic'], payload=json.dumps(data), qos=self.config['qos'], retain=bool(self.config['retain']),
hostname=self.config['broker'], port=self.config['port'], client_id=self.config['client_id'],
keepalive=self.config['keep_alive'], auth=auth or None, protocol=self.config['protocol'])
return True
def return_config_options(self):
config_option = [{'label': 'Broker',
'value': self.config['broker'],
'name': 'mqtt_broker',
'description': 'The hostname or IP address of the MQTT broker.',
'input_type': 'text'
},
{'label': 'Port',
'value': self.config['port'],
'name': 'mqtt_port',
'description': 'The network port for connecting to the MQTT broker.',
'input_type': 'number'
},
{'label': 'Protocol',
'value': self.config['protocol'],
'name': 'mqtt_protocol',
'description': 'The MQTT protocol version.',
'input_type': 'select',
'select_options': {'MQTTv31': '3.1',
'MQTTv311': '3.1.1'
}
},
{'label': 'Client ID',
'value': self.config['client_id'],
'name': 'mqtt_client_id',
'description': 'The client ID for connecting to the MQTT broker.',
'input_type': 'text'
},
{'label': 'Username',
'value': self.config['username'],
'name': 'mqtt_username',
'description': 'The username to authenticate with the MQTT broker.',
'input_type': 'text'
},
{'label': 'Password',
'value': self.config['password'],
'name': 'mqtt_password',
'description': 'The password to authenticate with the MQTT broker.',
'input_type': 'password'
},
{'label': 'Topic',
'value': self.config['topic'],
'name': 'mqtt_topic',
'description': 'The topic to publish notifications to.',
'input_type': 'text'
},
{'label': 'Quality of Service',
'value': self.config['qos'],
'name': 'mqtt_qos',
'description': 'The quality of service level to use when publishing the notification.',
'input_type': 'select',
'select_options': {0: 0,
1: 1,
2: 2
}
},
{'label': 'Retain Message',
'value': self.config['retain'],
'name': 'mqtt_retain',
'description': 'Set the message to be retained on the MQTT broker.',
'input_type': 'checkbox'
},
{'label': 'Keep-Alive',
'value': self.config['keep_alive'],
'name': 'mqtt_keep_alive',
'description': 'Maximum period in seconds before timing out the connection with the broker.',
'input_type': 'number'
}
]
return config_option
class NMA(Notifier):
"""
Notify My Android notifications
@ -3359,3 +3480,4 @@ def upgrade_config_to_db():
# Add a new notifier and update the config
notifier_id = add_notifier_config(agent_id=agent_id)
set_notifier_config(notifier_id=notifier_id, agent_id=agent_id, **notifier_config)