mirror of
https://github.com/nikdoof/aaisp2mqtt.git
synced 2025-12-17 12:49:22 +00:00
Cleanup and support Environment config
This commit is contained in:
161
aaisp-to-mqtt.py
161
aaisp-to-mqtt.py
@@ -1,133 +1,164 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import urllib
|
|
||||||
import time
|
import time
|
||||||
import configparser
|
import configparser
|
||||||
import paho.mqtt.client as mqtt
|
import paho.mqtt.client as mqtt
|
||||||
import humanfriendly
|
import humanfriendly
|
||||||
|
import requests
|
||||||
|
import argparse
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
VERSION = 0.1
|
VERSION = 0.2
|
||||||
|
|
||||||
|
AAISP_INFO_URL = 'https://chaos2.aa.net.uk/broadband/info'
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
logging.basicConfig(level=logging.INFO, format='%(levelname)8s [%(asctime)s] %(message)s')
|
logging.basicConfig(level=logging.INFO,
|
||||||
|
format='%(levelname)8s [%(asctime)s] %(message)s')
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) > 1:
|
||||||
LOG.fatal("Config file not supplied")
|
|
||||||
sys.exit(1)
|
|
||||||
cfgfile = sys.argv[1]
|
cfgfile = sys.argv[1]
|
||||||
# load the config
|
# load the config
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
config.read(cfgfile)
|
config.read(cfgfile)
|
||||||
|
|
||||||
# check it has the correct sections
|
# check it has the correct sections
|
||||||
for section in ["aaisp", "mqtt"]:
|
for section in ['aaisp', 'mqtt']:
|
||||||
if section not in config.sections():
|
if section not in config.sections():
|
||||||
LOG.fatal("%s section not found in config file %s", section, cfgfile)
|
LOG.fatal('%s section not found in config file %s',
|
||||||
|
section, cfgfile)
|
||||||
|
|
||||||
aaisp_username = config.get("aaisp", "username")
|
aaisp_username = config.get('aaisp', 'username')
|
||||||
aaisp_password = config.get("aaisp", "password")
|
aaisp_password = config.get('aaisp', 'password')
|
||||||
|
mqtt_broker = config.get('mqtt', 'broker')
|
||||||
|
mqtt_port = int(config.get('mqtt', 'port', fallback='1883'))
|
||||||
|
mqtt_username = config.get('mqtt', 'username', fallback=None)
|
||||||
|
mqtt_password = config.get('mqtt', 'password', fallback=None)
|
||||||
|
mqtt_topic_prefix = config.get('mqtt', 'topic_prefix', fallback='aaisp')
|
||||||
|
else:
|
||||||
|
# Use the environment
|
||||||
|
aaisp_username = os.environ.get('AAISP_USERNAME')
|
||||||
|
aaisp_password = os.environ.get('AAISP_PASSWORD')
|
||||||
|
mqtt_broker = os.environ.get('MQTT_BROKER') or 'localhost'
|
||||||
|
mqtt_port = int(os.environ.get('MQTT_PORT') or '1883')
|
||||||
|
mqtt_username = os.environ.get('MQTT_USERNAME')
|
||||||
|
mqtt_password = os.environ.get('MQTT_PASSWORD')
|
||||||
|
mqtt_topic_prefix = os.environ.get('MQTT_TOPIC_PREFIX') or 'aaisp'
|
||||||
|
|
||||||
|
if aaisp_username is None or aaisp_password is None:
|
||||||
|
LOG.fatal('Username or Password missing for AAISP')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
# attempt to get details from aaisp
|
# attempt to get details from aaisp
|
||||||
LOG.info("Connecting to AAISP CHAOSv2 endpoint")
|
LOG.info('Connecting to AAISP CHAOSv2 endpoint')
|
||||||
post_params = "control_login=%s&control_password=%s" % (aaisp_username, aaisp_password)
|
response = requests.get(AAISP_INFO_URL, params={
|
||||||
url = "https://chaos2.aa.net.uk/broadband/info"
|
'control_login': aaisp_username,
|
||||||
response = urllib.urlopen(url, data=post_params)
|
'control_password': aaisp_password
|
||||||
data = json.loads(response.read())
|
})
|
||||||
if "info" not in data:
|
if not response.status_code == requests.codes.ok:
|
||||||
LOG.fatal("info section not found in AAISP CHAOSv2 response")
|
LOG.error('Error connecting to AAISP CHAOSv2 endpoint: %s' % response.body)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
circuits = data["info"]
|
data = response.json()
|
||||||
LOG.info("Got %s circuits", len(circuits))
|
|
||||||
|
if 'info' not in data:
|
||||||
|
LOG.fatal('info section not found in AAISP CHAOSv2 response')
|
||||||
|
sys.exit(1)
|
||||||
|
circuits = data['info']
|
||||||
|
LOG.info('Got %s circuits', len(circuits))
|
||||||
if len(circuits) == 0:
|
if len(circuits) == 0:
|
||||||
LOG.fatal("No circuits returned from AAISP CHAOSv2")
|
LOG.fatal('No circuits returned from AAISP CHAOSv2')
|
||||||
|
|
||||||
# work out unique line IDs and logins
|
# work out unique line IDs and logins
|
||||||
logins = []
|
logins = []
|
||||||
lines = []
|
lines = []
|
||||||
for circuit in circuits:
|
for circuit in circuits:
|
||||||
if circuit["login"] not in logins:
|
if circuit['login'] not in logins:
|
||||||
logins.append(circuit["login"])
|
logins.append(circuit['login'])
|
||||||
if circuit["ID"] not in lines:
|
if circuit['ID'] not in lines:
|
||||||
lines.append(circuit["ID"])
|
lines.append(circuit['ID'])
|
||||||
LOG.info("* Lines: %s", ', '.join(lines))
|
LOG.info('* Lines: %s', ', '.join(lines))
|
||||||
LOG.info("* Logins: %s", ', '.join(logins))
|
LOG.info('* Logins: %s', ', '.join(logins))
|
||||||
|
|
||||||
|
|
||||||
# get MQTT config
|
|
||||||
mqtt_broker = config.get("mqtt", "broker")
|
|
||||||
mqtt_port = int(config.get("mqtt", "port"))
|
|
||||||
mqtt_username = config.get("mqtt", "username")
|
|
||||||
mqtt_password = config.get("mqtt", "password")
|
|
||||||
mqtt_topic_prefix = config.get("mqtt", "topic_prefix")
|
|
||||||
# connect to the broker
|
# connect to the broker
|
||||||
LOG.info("Connecting to MQTT broker %s:%s", mqtt_broker, mqtt_port)
|
LOG.info('Connecting to MQTT broker %s:%s', mqtt_broker, mqtt_port)
|
||||||
client = mqtt.Client()
|
client = mqtt.Client()
|
||||||
|
|
||||||
# do auth?
|
# do auth?
|
||||||
if mqtt_username is not None and mqtt_password is not None:
|
if mqtt_username is not None and mqtt_password is not None:
|
||||||
client.username_pw_set(mqtt_username, mqtt_password)
|
client.username_pw_set(mqtt_username, mqtt_password)
|
||||||
client.max_inflight_messages_set(100)
|
client.max_inflight_messages_set(100)
|
||||||
|
try:
|
||||||
client.connect(mqtt_broker, mqtt_port, 60)
|
client.connect(mqtt_broker, mqtt_port, 60)
|
||||||
LOG.info("Connected OK to MQTT")
|
except Exception:
|
||||||
|
LOG.exception('Error connecting to MQTT')
|
||||||
|
sys.exit(1)
|
||||||
|
LOG.info('Connected OK to MQTT')
|
||||||
|
|
||||||
# version and indexes
|
# version and indexes
|
||||||
publish(client=client, topic="%s/$version" % (mqtt_topic_prefix), payload=VERSION)
|
publish(client=client, topic='%s/$version' %
|
||||||
publish(client=client, topic="%s/$lines" % (mqtt_topic_prefix), payload=','.join(lines))
|
(mqtt_topic_prefix), payload=VERSION)
|
||||||
publish(client=client, topic="%s/$logins" % (mqtt_topic_prefix), payload=','.join(logins))
|
publish(client=client, topic='%s/$lines' %
|
||||||
LOG.info("Published version and index messages")
|
(mqtt_topic_prefix), payload=','.join(lines))
|
||||||
|
publish(client=client, topic='%s/$logins' %
|
||||||
|
(mqtt_topic_prefix), payload=','.join(logins))
|
||||||
|
LOG.info('Published version and index messages')
|
||||||
|
|
||||||
# publish per circuit
|
# publish per circuit
|
||||||
for circuit in circuits:
|
for circuit in circuits:
|
||||||
publish_per_circuit(client=client, circuit=circuit, mqtt_topic_prefix=mqtt_topic_prefix)
|
publish_per_circuit(client=client, circuit=circuit,
|
||||||
LOG.info("Published details for %s circuits", len(circuits))
|
mqtt_topic_prefix=mqtt_topic_prefix)
|
||||||
|
LOG.info('Published details for %s circuits', len(circuits))
|
||||||
# disconnect
|
# disconnect
|
||||||
LOG.info("Disconnecting from MQTT")
|
LOG.info('Disconnecting from MQTT')
|
||||||
client.disconnect()
|
client.disconnect()
|
||||||
|
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
def publish_per_circuit(client, circuit, mqtt_topic_prefix):
|
def publish_per_circuit(client, circuit, mqtt_topic_prefix):
|
||||||
quota_remaining = int(circuit["quota_remaining"])
|
quota_remaining = int(circuit['quota_remaining'])
|
||||||
quota_remaining_gb = quota_remaining / 1000000000
|
quota_remaining_gb = quota_remaining / 1000000000
|
||||||
quota_monthly = int(circuit["quota_monthly"])
|
quota_monthly = int(circuit['quota_monthly'])
|
||||||
quota_monthly_gb = quota_monthly / 1000000000
|
quota_monthly_gb = quota_monthly / 1000000000
|
||||||
up = float(circuit["rx_rate"])
|
up = float(circuit['rx_rate'])
|
||||||
up_mb = round(up / 1000000, 2)
|
up_mb = round(up / 1000000, 2)
|
||||||
down = float(circuit["tx_rate"])
|
down = float(circuit['tx_rate'])
|
||||||
down_mb = round(down / 1000000, 2)
|
down_mb = round(down / 1000000, 2)
|
||||||
|
|
||||||
# line_prefix = "%s/line/%s" % (mqtt_topic_prefix, circuit["ID"])
|
# line_prefix = '%s/line/%s' % (mqtt_topic_prefix, circuit['ID'])
|
||||||
login_prefix = "%s/login/%s" % (mqtt_topic_prefix, circuit["login"])
|
login_prefix = '%s/login/%s' % (mqtt_topic_prefix, circuit['login'])
|
||||||
for prefix in [login_prefix]: # , line_prefix]:
|
for prefix in [login_prefix]: # , line_prefix]:
|
||||||
for metric in [
|
for metric in [
|
||||||
("quota/remaining", quota_remaining),
|
('quota/remaining', quota_remaining),
|
||||||
("quota/remaining/gb", quota_remaining_gb),
|
('quota/remaining/gb', quota_remaining_gb),
|
||||||
("quota/remaining/human", humanfriendly.format_size(quota_remaining)),
|
('quota/remaining/human', humanfriendly.format_size(quota_remaining)),
|
||||||
("quota/monthly", quota_monthly),
|
('quota/monthly', quota_monthly),
|
||||||
("quota/monthly/gb", quota_monthly_gb),
|
('quota/monthly/gb', quota_monthly_gb),
|
||||||
("quota/monthly/human", humanfriendly.format_size(quota_monthly)),
|
('quota/monthly/human', humanfriendly.format_size(quota_monthly)),
|
||||||
("syncrate/up", up),
|
('syncrate/up', up),
|
||||||
("syncrate/up/mb", up_mb),
|
('syncrate/up/mb', up_mb),
|
||||||
("syncrate/up/human", humanfriendly.format_size(up)),
|
('syncrate/up/human', humanfriendly.format_size(up)),
|
||||||
("syncrate/down", down),
|
('syncrate/down', down),
|
||||||
("syncrate/down/mb", down_mb),
|
('syncrate/down/mb', down_mb),
|
||||||
("syncrate/down/human", humanfriendly.format_size(down)),
|
('syncrate/down/human', humanfriendly.format_size(down)),
|
||||||
("postcode", str(circuit["postcode"].strip()))
|
('postcode', str(circuit['postcode'].strip()))
|
||||||
]:
|
]:
|
||||||
topic = "%s/%s" % (prefix, metric[0])
|
topic = '%s/%s' % (prefix, metric[0])
|
||||||
publish(client=client, topic=topic, payload=metric[1])
|
publish(client=client, topic=topic, payload=metric[1])
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def publish(client, topic, payload):
|
def publish(client, topic, payload):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
result = client.publish(topic=topic, payload=payload, qos=1)
|
result = client.publish(topic=topic, payload=payload, qos=1)
|
||||||
if result[0] != 0:
|
if result[0] != 0:
|
||||||
LOG.fail("MQTT publish failure: %s %s" , topic, payload)
|
LOG.fail('MQTT publish failure: %s %s', topic, payload)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
paho-mqtt>=1.2
|
paho-mqtt>=1.2
|
||||||
configparser>=3.5.0
|
configparser>=3.5.0
|
||||||
humanfriendly>=2.1
|
humanfriendly>=2.1
|
||||||
|
requests>=2.23.0
|
||||||
|
|||||||
Reference in New Issue
Block a user