├── BlueTooth ├── README.md ├── bluemaestroscan.py ├── mqtt.bluetooth.py ├── mqtt.homie.bluetooth.noloop.py └── mqtt.homie.bluetooth.py ├── README.md ├── mqtt.dhtsensor.py ├── mqtt.fancontrol.py ├── mqtt.homie.dhtsensor.noloop.py ├── mqtt.homie.dhtsensor.py └── mqtt.homie.fancontrol.py /BlueTooth/README.md: -------------------------------------------------------------------------------- 1 | These files are code for accessing a BLE beacon and passing the values via MQTT transport for use in OpenHAB. 2 | 3 | Currently the scan file is specific for a Blue Maestro Tempo Disc. 4 | -------------------------------------------------------------------------------- /BlueTooth/bluemaestroscan.py: -------------------------------------------------------------------------------- 1 | # BlueMastro Tempo Disc Advertising packet decoder 2 | # Called from bluemaestro.py 3 | # This class has the specificis for decoding the advertising packets for the Blue Maestro Tempo Disc https://www.bluemaestro.com/product/tempo-disc-temperature/ 4 | # Unsure if there are any other Blue Maestro products that it would work with. 5 | # David@andc.nz 15/12/2016 6 | 7 | DEBUG = True 8 | # BLE Scanner based on from JCS 06/07/14 9 | # BLE scanner based on https://github.com/adamf/BLE/blob/master/ble-scanner.py 10 | # BLE scanner, based on https://code.google.com/p/pybluez/source/browse/trunk/examples/advanced/inquiry-with-rssi.py 11 | 12 | # https://github.com/pauloborges/bluez/blob/master/tools/hcitool.c for lescan 13 | # https://kernel.googlesource.com/pub/scm/bluetooth/bluez/+/5.6/lib/hci.h for opcodes 14 | # https://github.com/pauloborges/bluez/blob/master/lib/hci.c#L2782 for functions used by lescan 15 | 16 | # performs a simple device inquiry, and returns a list of ble advertizements 17 | # discovered device 18 | 19 | # NOTE: Python's struct.pack() will add padding bytes unless you make the endianness explicit. Little endian 20 | # should be used for BLE. Always start a struct.pack() format string with "<" 21 | 22 | import collections 23 | import os 24 | import sys 25 | import struct 26 | import bluetooth._bluetooth as bluez 27 | 28 | LE_META_EVENT = 0x3e 29 | LE_PUBLIC_ADDRESS=0x00 30 | LE_RANDOM_ADDRESS=0x01 31 | LE_SET_SCAN_PARAMETERS_CP_SIZE=7 32 | OGF_LE_CTL=0x08 33 | OCF_LE_SET_SCAN_PARAMETERS=0x000B 34 | OCF_LE_SET_SCAN_ENABLE=0x000C 35 | OCF_LE_CREATE_CONN=0x000D 36 | 37 | LE_ROLE_MASTER = 0x00 38 | LE_ROLE_SLAVE = 0x01 39 | 40 | # these are actually subevents of LE_META_EVENT 41 | EVT_LE_CONN_COMPLETE=0x01 42 | EVT_LE_ADVERTISING_REPORT=0x02 43 | EVT_LE_CONN_UPDATE_COMPLETE=0x03 44 | EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE=0x04 45 | 46 | # Advertisment event types 47 | ADV_IND=0x00 48 | ADV_DIRECT_IND=0x01 49 | ADV_SCAN_IND=0x02 50 | ADV_NONCONN_IND=0x03 51 | ADV_SCAN_RSP=0x04 52 | 53 | 54 | def returnnumberpacket(pkt): 55 | myInteger = 0 56 | multiple = 256 57 | for c in pkt: 58 | myInteger += struct.unpack("B",c)[0] * multiple 59 | multiple = 1 60 | return myInteger 61 | 62 | def returnstringpacket(pkt): 63 | myString = ""; 64 | for c in pkt: 65 | myString += "%02x" %struct.unpack("B",c)[0] 66 | return myString 67 | 68 | def printpacket(pkt): 69 | for c in pkt: 70 | sys.stdout.write("%02x " % struct.unpack("B",c)[0]) 71 | 72 | def get_packed_bdaddr(bdaddr_string): 73 | packable_addr = [] 74 | addr = bdaddr_string.split(':') 75 | addr.reverse() 76 | for b in addr: 77 | packable_addr.append(int(b, 16)) 78 | return struct.pack(" 0: 52 | print "%s/temperature = %.2f" % (returnedList["mac"],returnedList["temp"]) 53 | # Publish to the MQTT channel 54 | try: 55 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT); 56 | print 'Updating temp for {0} to {1}'.format(returnedList["mac"],float(returnedList["temp"])) 57 | (result1,mid) = mqttc.publish("%s/temperature" % returnedList["mac"],float(returnedList["temp"])) 58 | time.sleep(1) 59 | 60 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT); 61 | (result2,mid) = mqttc.publish("%s/humidity" % returnedList["mac"],float(returnedList["humidity"])) 62 | print 'Updating humidity {0} = {1}'.format(returnedList["mac"],float(returnedList["humidity"])) 63 | time.sleep(1) 64 | 65 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT); 66 | (result3,mid) = mqttc.publish("%s/dewpoint" % returnedList["mac"],float(returnedList["dewpoint"])) 67 | print 'Updating {0}/dewpoint = {1}'.format( returnedList["mac"],returnedList["dewpoint"]) 68 | time.sleep(1) 69 | 70 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT); 71 | (result4,mid) = mqttc.publish("%s/name" % returnedList["mac"],returnedList["name"]) 72 | print 'Updating name {0}/name = {1}'.format(returnedList["mac"],returnedList["name"]) 73 | time.sleep(1) 74 | 75 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT); 76 | (result5,mid) = mqttc.publish("%s/battery" % returnedList["mac"],float(returnedList["battery"])) 77 | print 'Updating battery {0}/battery = {1}'.format(returnedList["mac"],float(returnedList["battery"])) 78 | print 'Updated Battery' 79 | #print 'MQTT Updated result {0} and {1} and {2} and {3} and {4} and {5}'.format(result1,result2,result3,result4,result5) 80 | 81 | if result1 == 1 or result2 == 1 or result3 == 1 or result4 == 1 or result5 ==1: 82 | raise ValueError('Result for one message was not 0') 83 | # mqttc.disconnect() 84 | print "Sleeping for %d seconds" % FREQUENCY_SECONDS 85 | time.sleep(FREQUENCY_SECONDS) 86 | mqttc.loop(1) 87 | 88 | 89 | except Exception,e: 90 | # Null out the worksheet so a login is performed at the top of the loop. 91 | mqttc.disconnect() 92 | print('Append error, logging in again: ' + str(e)) 93 | print "Sleeping for 60 seconds" 94 | time.sleep(60) 95 | continue 96 | else: 97 | print "Sleeping for 30 seconds" 98 | time.sleep(30) 99 | except Exception,e: 100 | # Error appending data, most likely because credentials are stale. 101 | # Null out the worksheet so a login is performed at the top of the loop. 102 | print('Append error, logging in again: ' + str(e)) 103 | print "Sleeping for 60 seconds" 104 | time.sleep(60) 105 | continue 106 | 107 | -------------------------------------------------------------------------------- /BlueTooth/mqtt.homie.bluetooth.noloop.py: -------------------------------------------------------------------------------- 1 | # Blue Maestro Tempo Disk Scanner for MQTT 2 | # Takes all values from the scanned tempo disc and using the MAC id pushes each topic into MQTT 3 | # requires paho.mqtt client and bluez. 4 | # Also requires bluemaestroscan.py in th esame directory as this has the specifics for decoding 5 | # the advertising packets for the Blue Maestro Tempo Disc https://www.bluemaestro.com/product/tempo-disc-temperature/ 6 | # Unsure if there are any other Blue Maetro products that it would work with. 7 | # David@andc.nz 15/12/2016 8 | 9 | 10 | # Credit jcs 6/8/2014 as basis 11 | 12 | import bluemaestroscan #specific bluemaestro tempo disc scanner 13 | import json 14 | import sys 15 | import argparse 16 | import time 17 | import homie 18 | import bluetooth._bluetooth as bluez 19 | 20 | dev_id = 0 21 | FREQUENCY_SECONDS = 600 22 | 23 | def main(configfile='homie-bluetooth.json'): 24 | Homie = homie.Homie(configfile) 25 | Homie.setFirmware("bluemaestro-temperature","1.0.0") 26 | Homie.setup() 27 | 28 | try: 29 | sock = bluez.hci_open_dev(dev_id) 30 | print "ble thread started" 31 | 32 | except: 33 | print "error accessing bluetooth device..." 34 | sys.exit(1) 35 | 36 | bluemaestroscan.hci_le_set_scan_parameters(sock) 37 | bluemaestroscan.hci_enable_le_scan(sock) 38 | 39 | 40 | try: 41 | returnedList = bluemaestroscan.parse_events(sock, 2) 42 | nodes = {} 43 | print "-------------------------------------------------------------------------------------------------------" 44 | mac = "" 45 | temp = 0 46 | currentdate = time.strftime('%Y-%m-%d %H:%M:%S') 47 | print('Date Time: {0}'.format(currentdate)) 48 | for beacon in returnedList: 49 | val = returnedList[beacon] 50 | print beacon, val 51 | mac = returnedList["mac"] 52 | temp = returnedList["temp"] 53 | 54 | print "number of beacons found {0}".format(len(returnedList)) 55 | if len(returnedList) > 0: 56 | print "%s/temperature = %.2f" % (returnedList["mac"],returnedList["temp"]) 57 | # Publish to the MQTT channel 58 | try: 59 | temperatureNode = Homie.Node(mac,"temperature") 60 | Homie.setNodeProperty(temperatureNode,"temperature",float(returnedList["temp"]),True) 61 | print 'Updating temp for {0} to {1}'.format(returnedList["mac"],float(returnedList["temp"])) 62 | humidityNode = Homie.Node(mac,"humidity") 63 | Homie.setNodeProperty(humidityNode,"humidity",float(returnedList["humidity"]),True) 64 | print 'Updating humidity {0} = {1}'.format(returnedList["mac"],float(returnedList["humidity"])) 65 | batteryNode = Homie.Node(mac,"battery") 66 | Homie.setNodeProperty(batteryNode,"battery",float(returnedList["battery"]),True) 67 | print 'Updating battery {0}/battery = {1}'.format(returnedList["mac"],float(returnedList["battery"])) 68 | dewpointNode = Homie.Node(mac,"dewpoint") 69 | Homie.setNodeProperty(dewpointNode,"dewpoint",float(returnedList["dewpoint"]),True) 70 | print 'Updating {0}/dewpoint = {1}'.format( returnedList["mac"],returnedList["dewpoint"]) 71 | nameNode = Homie.Node(mac,"name") 72 | Homie.setNodeProperty(nameNode,"name",returnedList["name"],True) 73 | print 'Updating name {0}/name = {1}'.format(returnedList["mac"],returnedList["name"]) 74 | time.sleep(1) 75 | 76 | print "Sleeping for %d seconds" % FREQUENCY_SECONDS 77 | 78 | except Exception,e: 79 | # Null out the worksheet so a login is performed at the top of the loop. 80 | print('Append error, logging in again: ' + str(e)) 81 | print "Sleeping for 60 seconds" 82 | 83 | except Exception,e: 84 | # Error appending data, most likely because credentials are stale. 85 | # Null out the worksheet so a login is performed at the top of the loop. 86 | print('Append error, logging in again: ' + str(e)) 87 | print "Sleeping for 60 seconds" 88 | 89 | if __name__ == '__main__': 90 | try: 91 | parser= argparse.ArgumentParser(description="Homie Based Bluetooth Reader") 92 | parser.add_argument('-c','--configfile', help='Configuration filename (json)',required=True) 93 | args = parser.parse_args() 94 | main(args.configfile) 95 | except (KeyboardInterrupt, SystemExit): 96 | print "quitting." 97 | 98 | -------------------------------------------------------------------------------- /BlueTooth/mqtt.homie.bluetooth.py: -------------------------------------------------------------------------------- 1 | # Blue Maestro Tempo Disk Scanner for MQTT 2 | # Takes all values from the scanned tempo disc and using the MAC id pushes each topic into MQTT 3 | # requires paho.mqtt client and bluez. 4 | # Also requires bluemaestroscan.py in th esame directory as this has the specifics for decoding 5 | # the advertising packets for the Blue Maestro Tempo Disc https://www.bluemaestro.com/product/tempo-disc-temperature/ 6 | # Unsure if there are any other Blue Maetro products that it would work with. 7 | # David@andc.nz 15/12/2016 8 | 9 | 10 | # Credit jcs 6/8/2014 as basis 11 | 12 | import bluemaestroscan #specific bluemaestro tempo disc scanner 13 | import json 14 | import sys 15 | import argparse 16 | import time 17 | import logging 18 | import homie 19 | import bluetooth._bluetooth as bluez 20 | 21 | dev_id = 0 22 | FREQUENCY_SECONDS = 600 23 | LOG = "/var/log/mqtt.home.bluetooth.log" 24 | 25 | def updatenode(Homie, nodelist,mac,nodevalue,newvalue): 26 | if mac+nodevalue in nodelist: 27 | logging.info("Found existing " + nodevalue + " node: " + mac) 28 | print("Found existing " + nodevalue + " node: " + mac) 29 | currentNode = nodelist[mac+nodevalue] 30 | print ("Obtained node for updating " + mac) 31 | Homie.setNodeProperty(currentNode,nodevalue,newvalue,True) 32 | else: 33 | logging.info("Added new " + nodevalue + "for mac " + mac) 34 | print("Adding new " + nodevalue + "node for mac " + mac) 35 | currentNode = Homie.Node(mac,nodevalue) 36 | Homie.setNodeProperty(currentNode,nodevalue,newvalue,True) 37 | nodelist[mac+nodevalue] = currentNode 38 | print("Added new " + nodevalue + " node for mac" + mac) 39 | 40 | 41 | def main(configfile='homie-bluetooth.json'): 42 | Homie = homie.Homie(configfile) 43 | Homie.setFirmware("bluemaestro-temperature","1.0.0") 44 | Homie.setup() 45 | json_data=open(configfile).read() 46 | data = json.loads(json_data) 47 | FREQUENCY_SECONDS =data["bluetooth"]["frequency"] 48 | LOG = data["bluetooth"]["log"] 49 | logging.basicConfig(filename=LOG, level=logging.INFO,format='%(asctime)s %(levelname)s %(message)s') 50 | 51 | 52 | try: 53 | sock = bluez.hci_open_dev(dev_id) 54 | logging.info("ble thread started") 55 | 56 | except: 57 | print "error accessing bluetooth device..." 58 | logging.info("error accessing bluetooth device...") 59 | sys.exit(1) 60 | 61 | bluemaestroscan.hci_le_set_scan_parameters(sock) 62 | bluemaestroscan.hci_enable_le_scan(sock) 63 | 64 | 65 | while True: 66 | try: 67 | returnedList = bluemaestroscan.parse_events(sock, 2) 68 | nodes = {} 69 | print "-------------------------------------------------------------------------------------------------------" 70 | logging.info("-------------------------------------------------------------------------------------------------------") 71 | mac = "" 72 | temp = 0 73 | currentdate = time.strftime('%Y-%m-%d %H:%M:%S') 74 | print('Date Time: {0}'.format(currentdate)) 75 | logging.info('Date Time: {0}'.format(currentdate)) 76 | for beacon in returnedList: 77 | val = returnedList[beacon] 78 | print beacon, val 79 | mac = returnedList["mac"] 80 | temp = returnedList["temp"] 81 | 82 | print "number of beacons found {0}".format(len(returnedList)) 83 | logging.info("number of beacons found {0}".format(len(returnedList))) 84 | if len(returnedList) > 0: 85 | print "%s/temperature = %.2f" % (returnedList["mac"],returnedList["temp"]) 86 | logging.info("%s/temperature = %.2f" % (returnedList["mac"],returnedList["temp"])) 87 | # Publish to the MQTT channel 88 | try: 89 | print("CHecking nodes for " + mac+"temperature") 90 | updatenode(Homie, nodes,mac,"temperature",float(returnedList["temp"])) 91 | 92 | #if mac+"temperature" in nodes: 93 | # logging.info("Found existing temperature node: " + mac+"temperature") 94 | # print("Found existing temperature node: " + mac+"temperature") 95 | # temperatureNode = nodes[mac+"temperature"] 96 | # print ("Obtained temperature node for updating") 97 | # Homie.setNodeProperty(tempNode,"temperature",float(returnedList["temp"]),True) 98 | #else: 99 | # logging.info("Added new temperature node for mac" + mac) 100 | # print("Adding new temperature node for mac" + mac) 101 | # temperatureNode = Homie.Node(mac,"temperature") 102 | # Homie.setNodeProperty(temperatureNode,"temperature",float(returnedList["temp"]),True) 103 | # nodes[mac+"temperature"] = temperatureNode 104 | # print("Added new temperature node for mac" + mac) 105 | print 'Updating temp for {0} to {1}'.format(returnedList["mac"],float(returnedList["temp"])) 106 | logging.info('Updating temp for {0} to {1}'.format(returnedList["mac"],float(returnedList["temp"]))) 107 | 108 | print("CHecking nodes for " + mac+"humidity") 109 | updatenode(Homie, nodes,mac,"humidity",float(returnedList["humidity"])) 110 | #humidityNode = Homie.Node(mac,"humidity") 111 | #Homie.setNodeProperty(humidityNode,"humidity",float(returnedList["humidity"]),True) 112 | print 'Updating humidity {0} = {1}'.format(returnedList["mac"],float(returnedList["humidity"])) 113 | logging.info('Updating humidity {0} = {1}'.format(returnedList["mac"],float(returnedList["humidity"]))) 114 | 115 | print("CHecking nodes for " + mac+"battery") 116 | updatenode(Homie, nodes,mac,"battery",float(returnedList["battery"])) 117 | 118 | #batteryNode = Homie.Node(mac,"battery") 119 | #Homie.setNodeProperty(batteryNode,"battery",float(returnedList["battery"]),True) 120 | print 'Updating battery {0}/battery = {1}'.format(returnedList["mac"],float(returnedList["battery"])) 121 | logging.info('Updating battery {0}/battery = {1}'.format(returnedList["mac"],float(returnedList["battery"]))) 122 | 123 | print("CHecking nodes for " + mac+"dewpoint") 124 | updatenode(Homie, nodes,mac,"dewpoint",float(returnedList["dewpoint"])) 125 | #dewpointNode = Homie.Node(mac,"dewpoint") 126 | #Homie.setNodeProperty(dewpointNode,"dewpoint",float(returnedList["dewpoint"]),True) 127 | print 'Updating {0}/dewpoint = {1}'.format( returnedList["mac"],returnedList["dewpoint"]) 128 | logging.info('Updating {0}/dewpoint = {1}'.format( returnedList["mac"],returnedList["dewpoint"])) 129 | 130 | print("CHecking nodes for " + mac+"name") 131 | updatenode(Homie, nodes,mac,"name",returnedList["name"]) 132 | 133 | #nameNode = Homie.Node(mac,"name") 134 | #Homie.setNodeProperty(nameNode,"name",returnedList["name"],True) 135 | print 'Updating name {0}/name = {1}'.format(returnedList["mac"],returnedList["name"]) 136 | logging.info('Updating name {0}/name = {1}'.format(returnedList["mac"],returnedList["name"])) 137 | time.sleep(1) 138 | 139 | except Exception,e: 140 | # Null out the worksheet so a login is performed at the top of the loop. 141 | logging.error('Append error, logging in again: ' + str(e)) 142 | logging.error("Sleeping for 60 seconds") 143 | time.sleep(60) 144 | continue 145 | else: 146 | print "Sleeping for 30 seconds" 147 | logging.info("Sleeping for 30 seconds" ) 148 | time.sleep(30) 149 | logging.info("Sleeping for %s seconds" % FREQUENCY_SECONDS) 150 | print("Sleeping for %s seconds" % FREQUENCY_SECONDS) 151 | time.sleep(FREQUENCY_SECONDS) 152 | 153 | except Exception,e: 154 | # Error appending data, most likely because credentials are stale. 155 | # Null out the worksheet so a login is performed at the top of the loop. 156 | print('Append error, logging in again: ' + str(e)) 157 | print "Sleeping for 60 seconds" 158 | time.sleep(60) 159 | continue 160 | 161 | if __name__ == '__main__': 162 | try: 163 | parser= argparse.ArgumentParser(description="Homie Based Bluetooth Reader") 164 | parser.add_argument('-c','--configfile', help='Configuration filename (json)',required=True) 165 | args = parser.parse_args() 166 | main(args.configfile) 167 | except (KeyboardInterrupt, SystemExit): 168 | print "quitting." 169 | 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository is my Collection of scripts used for OpenHAB (or any other purpose). 2 | They will most likely use MQTT as a transport, and therfore will be quite generic. 3 | 4 | They are intended for use on remote devices (raspberry PI for example) for sending sensor information or responding to commands. 5 | -------------------------------------------------------------------------------- /mqtt.dhtsensor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # DHT Sensor Data-logging to MQTT Temperature channel 3 | 4 | # Requies a Mosquitto Server Install On the destination. 5 | 6 | # Copyright (c) 2014 Adafruit Industries 7 | # Author: Tony DiCola 8 | # MQTT Encahncements: David Cole (2016) 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | import json 28 | import requests 29 | import sys 30 | import time 31 | import datetime 32 | import paho.mqtt.client as mqtt 33 | import Adafruit_DHT 34 | 35 | 36 | #================================================================================================================================================== 37 | #Usage 38 | #python mqtt.channel.py 39 | # eg python mqtt.channel.py 'cupboard/temperature1' 'cupboard/humidity1' 4 40 | # will start an instance using 'cupboard/temperature1' as the temperature topic, and using gpio port 4 to talk to a DHT22 sensor 41 | # it will use the default update time of 300 secons. 42 | #================================================================================================================================================== 43 | 44 | # Type of sensor, can be Adafruit_DHT.DHT11, Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302. 45 | DHT_TYPE = Adafruit_DHT.DHT22 46 | 47 | # Example of sensor connected to Raspberry Pi pin 23 48 | DHT_PIN = sys.argv[3] 49 | # Example of sensor connected to Beaglebone Black pin P8_11 50 | #DHT_PIN = 'P8_11' 51 | 52 | if (len(sys.argv) < 2): 53 | raise ValueError('Input arguments of mqtt channel temperature humidity not passed') 54 | 55 | MOSQUITTO_HOST = 'servername' 56 | MOSQUITTO_PORT = 1883 57 | MOSQUITTO_TEMP_MSG = str(sys.argv[1]) # Old channel name in here 58 | MOSQUITTO_HUMI_MSG = str(sys.argv[2]) # Old channel name now passed by argument 59 | MOSQUITTO_BASE_TOPIC = str(sys.argv[1]).split('/') # Extract the base topic 60 | MOSQUITTO_LWT_TOPIC = MOSQUITTO_BASE_TOPIC[0] + '/LWT' #Create the last-will-and-testament topic 61 | print('Mosquitto Temp MSG {0}'.format(MOSQUITTO_TEMP_MSG)) 62 | print('Mosquitto Humidity MSG {0}'.format(MOSQUITTO_HUMI_MSG)) 63 | print('Mosquitto LWT MSG {0}'.format(MOSQUITTO_LWT_TOPIC)) 64 | 65 | # How long to wait (in seconds) between measurements. 66 | print "Args length: " + str(len(sys.argv)) 67 | FREQUENCY_SECONDS = 300 68 | 69 | if (len(sys.argv) > 4): 70 | FREQUENCY_SECONDS = float(sys.argv[4]) 71 | 72 | 73 | print('Logging sensor measurements to {0} every {1} seconds.'.format('MQTT', FREQUENCY_SECONDS)) 74 | print('Press Ctrl-C to quit.') 75 | print('Connecting to MQTT on {0}'.format(MOSQUITTO_HOST)) 76 | mqttc = mqtt.Client("python_pub") 77 | mqttc.will_set(MOSQUITTO_LWT_TOPIC, payload='offline', qos=0, retain=True) 78 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT, keepalive=FREQUENCY_SECONDS+10) 79 | mqttc.publish(MOSQUITTO_LWT_TOPIC, payload='online', qos=0, retain=True) 80 | try: 81 | 82 | while True: 83 | # Attempt to get sensor reading. 84 | humidity, temp = Adafruit_DHT.read(DHT_TYPE, DHT_PIN) 85 | 86 | # Skip to the next reading if a valid measurement couldn't be taken. 87 | # This might happen if the CPU is under a lot of load and the sensor 88 | # can't be reliably read (timing is critical to read the sensor). 89 | if humidity is None or temp is None: 90 | time.sleep(2) 91 | continue 92 | 93 | currentdate = time.strftime('%Y-%m-%d %H:%M:%S') 94 | print('Date Time: {0}'.format(currentdate)) 95 | print('Temperature: {0:0.2f} C'.format(temp)) 96 | print('Humidity: {0:0.2f} %'.format(humidity)) 97 | 98 | # Publish to the MQTT channel 99 | try: 100 | print 'Updating {0}'.format(MOSQUITTO_TEMP_MSG) 101 | (result1,mid) = mqttc.publish(MOSQUITTO_TEMP_MSG,temp) 102 | print 'Updating {0}'.format(MOSQUITTO_HUMI_MSG) 103 | time.sleep(1) 104 | (result2,mid) = mqttc.publish(MOSQUITTO_HUMI_MSG,humidity) 105 | print 'MQTT Updated result {0} and {1}'.format(result1,result2) 106 | if result1 == 1 or result2 == 1: 107 | raise ValueError('Result for one message was not 0') 108 | 109 | except Exception,e: 110 | # Error appending data, most likely because credentials are stale. 111 | # Null out the worksheet so a login is performed at the top of the loop. 112 | print('Append error, logging in again: ' + str(e)) 113 | continue 114 | 115 | # Wait 30 seconds before continuing 116 | print('Wrote a message to MQTT broker') 117 | time.sleep(FREQUENCY_SECONDS) 118 | 119 | except Exception as e: 120 | print('Error connecting to the MQTT server: {0}'.format(e)) 121 | 122 | -------------------------------------------------------------------------------- /mqtt.fancontrol.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | import sys 3 | from time import sleep 4 | import random 5 | import paho.mqtt.client as mqtt 6 | import logging 7 | 8 | 9 | 10 | # The callback for when a PUBLISH message is received from the server. 11 | def on_message(client, userdata, msg): 12 | print('topic') 13 | logging.info('Topic: ' + msg.topic+' Message: '+str(msg.payload)) 14 | print('Topic: ' + msg.topic+' Message: '+str(msg.payload)) 15 | if msg.payload == "1": 16 | print 'turning fan on' 17 | logging.info("Turning Fan on") 18 | fan.ChangeDutyCycle(100) 19 | (result1,mid) = client.publish("cupboard/fanstate","ON") 20 | print "After mqtt: %d mid: %d" %(result1 , mid) 21 | else: 22 | logging.info("Turning fan off") 23 | print 'turning fan off' 24 | fan.ChangeDutyCycle(0) 25 | client.publish("cupboard/fanstate",0) 26 | (result1,mid) = client.publish("cupboard/fanstate","OFF") 27 | print "After mqtt: %d mid: %d" %(result1 , mid) 28 | 29 | 30 | # The callback for when the client receives a CONNACK response from the server. 31 | def on_connect(client, userdata, rc): 32 | logging.info("Connected with result code "+str(rc)) 33 | # Subscribing in on_connect() means that if we lose the connection and 34 | # reconnect then subscriptions will be renewed. 35 | client.subscribe('cupboard/fan',1) 36 | 37 | logging.basicConfig(filename="/var/log/fancontrol.log", level=logging.INFO,format='%(asctime)s %(levelname)s %(message)s') 38 | GPIO.setwarnings(False) 39 | GPIO.setmode(GPIO.BCM) ## Indicates which pin numbering configuration to use 40 | 41 | MOSQUITTO_HOST = 'mqttserver' 42 | MOSQUITTO_PORT = 1883 43 | 44 | fanMouth = 18 45 | turnedon = 0 46 | logging.info("Setting up GPIO ports") 47 | print("Setting up GPIO ports") 48 | GPIO.setup(fanMouth, GPIO.OUT) 49 | GPIO.output(fanMouth,GPIO.HIGH) 50 | 51 | fan = GPIO.PWM(fanMouth, 100) 52 | 53 | fan.start(0) 54 | PAUSE_TIME = 60.02 55 | 56 | print('Receiving commands to start stop fan') 57 | print('Press Ctrl-C to quit.') 58 | logging.info('Connecting to MQTT on {0}'.format(MOSQUITTO_HOST)) 59 | print('Connecting to MQTT on {0}'.format(MOSQUITTO_HOST)) 60 | mqttc = mqtt.Client() 61 | mqttc.on_message = on_message 62 | mqttc.on_connect = on_connect 63 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT) 64 | while True: 65 | try: 66 | mqttc.loop_forever() 67 | 68 | except Exception,e: 69 | # Error appending data, most likely because credentials are stale. 70 | # Null out the worksheet so a login is performed at the top of the lo 71 | logging.error("Error in mqtt loop") 72 | mqttc.disconnect() 73 | mqttc.connect(MOSQUITTO_HOST,MOSQUITTO_PORT) 74 | print('Append error, logging in again: ' + str(e)) 75 | continue 76 | 77 | 78 | except KeyboardInterrupt: 79 | print("error") 80 | GPIO.cleanup() 81 | exit(0) 82 | 83 | -------------------------------------------------------------------------------- /mqtt.homie.dhtsensor.noloop.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # DHT Sensor Data-logging to MQTT Temperature channel 3 | 4 | # Requies a Mosquitto Server Install On the destination. 5 | 6 | # Copyright (c) 2014 Adafruit Industries 7 | # Author: Tony DiCola 8 | # MQTT Encahncements: David Cole (2016) 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | import json 28 | import requests 29 | import sys 30 | import argparse 31 | import time 32 | import datetime 33 | import homie 34 | import Adafruit_DHT 35 | 36 | #================================================================================================================================================== 37 | #Usage python mqtt.channel.py # Type of sensor, can be 38 | #Adafruit_DHT.DHT11, Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302. 39 | # eg python mqtt.channel.py 'cupboard/temperature1' 'cupboard/humidity1' 4DHT_TYPE = Adafruit_DHT.DHT22 will start an instance using 40 | #'cupboard/temperature1' as the temperature topic, and using gpio port 4 to talk to a DHT22 sensor Example of sensor connected to 41 | #Raspberry Pi pin 23 it will use the default update time of 300 secons.DHT_PIN = sys.argv[3] Example of sensor connected to Beaglebone 42 | #Black pin P8_11 DHT_PIN = 'P8_11' 43 | #================================================================================================================================================== 44 | # Type of sensor, can be Adafruit_DHT.DHT11, Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302. 45 | DHT_TYPE = Adafruit_DHT.DHT22 46 | 47 | # Example of sensor connected to Raspberry Pi pin 23 48 | DHT_PIN = 4 49 | # Example of sensor connected to Beaglebone Black pin P8_11 50 | #DHT_PIN = 'P8_11' 51 | 52 | 53 | # How long to wait (in seconds) between measurements. 54 | FREQUENCY_SECONDS = 200 55 | 56 | def main(configfile='homie-dht.json'): 57 | Homie = homie.Homie(configfile) 58 | temperatureNode = Homie.Node("temperature","temperature") 59 | humidityNode = Homie.Node("humidity","humidity") 60 | 61 | json_data=open(configfile).read() 62 | data = json.loads(json_data) 63 | FREQUENCY_SECONDS =data["dht"]["frequency"] 64 | DHT_PIN = data["dht"]["pin"] 65 | print('Logging sensor measurements to mqtt.') 66 | Homie.setFirmware("dht-temperature","1.0.0") 67 | Homie.setup() 68 | try: 69 | # Attempt to get sensor reading. 70 | notfound = True 71 | while notfound: 72 | print('Performing read on dht') 73 | humidity, temp = Adafruit_DHT.read(DHT_TYPE, DHT_PIN) 74 | print('After dht read') 75 | 76 | # Skip to the next reading if a valid measurement couldn't be taken. 77 | # This might happen if the CPU is under a lot of load and the sensor 78 | # can't be reliably read (timing is critical to read the sensor). 79 | if humidity is None or temp is None: 80 | time.sleep(2) 81 | print "Nothing received from sensor" 82 | else: 83 | notfound = False 84 | 85 | currentdate = time.strftime('%Y-%m-%d %H:%M:%S') 86 | print('Date Time: {0}'.format(currentdate)) 87 | print('Temperature: {0:0.2f} C'.format(temp)) 88 | print('Humidity: {0:0.2f} %'.format(humidity)) 89 | 90 | # Publish to the MQTT channel 91 | print('Connecting to host') 92 | print("Posting Temperature to homie") 93 | Homie.setNodeProperty(temperatureNode,"degrees",temp,True) 94 | Homie.setNodeProperty(humidityNode,"humidity",humidity,True) 95 | 96 | except Exception,e: 97 | # Error appending data, most likely because credentials are stale. 98 | # Null out the worksheet so a login is performed at the top of the loop. 99 | print('Append error, logging in again: ' + str(e)) 100 | else: 101 | # Wait 30 seconds before continuing 102 | print('Wrote a message tp MQQTT') 103 | 104 | if __name__ == '__main__': 105 | try: 106 | parser= argparse.ArgumentParser(description="Homie Based DHT Reader") 107 | parser.add_argument('-c','--configfile', help='Configuration filename (json)',required=True) 108 | args = parser.parse_args() 109 | main(args.configfile) 110 | except (KeyboardInterrupt, SystemExit): 111 | print "quitting." 112 | 113 | -------------------------------------------------------------------------------- /mqtt.homie.dhtsensor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # DHT Sensor Data-logging to MQTT Temperature channel 3 | 4 | # Requies a Mosquitto Server Install On the destination. 5 | 6 | # Copyright (c) 2014 Adafruit Industries 7 | # Author: Tony DiCola 8 | # MQTT Encahncements: David Cole (2016) 9 | 10 | # Permission is hereby granted, free of charge, to any person obtaining a copy 11 | # of this software and associated documentation files (the "Software"), to deal 12 | # in the Software without restriction, including without limitation the rights 13 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | # copies of the Software, and to permit persons to whom the Software is 15 | # furnished to do so, subject to the following conditions: 16 | 17 | # The above copyright notice and this permission notice shall be included in all 18 | # copies or substantial portions of the Software. 19 | 20 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | # SOFTWARE. 27 | import json 28 | import requests 29 | import sys 30 | import argparse 31 | import time 32 | import datetime 33 | import homie 34 | import Adafruit_DHT 35 | 36 | #================================================================================================================================================== 37 | #Usage python mqtt.channel.py # Type of sensor, can be 38 | #Adafruit_DHT.DHT11, Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302. 39 | # eg python mqtt.channel.py 'cupboard/temperature1' 'cupboard/humidity1' 4DHT_TYPE = Adafruit_DHT.DHT22 will start an instance using 40 | #'cupboard/temperature1' as the temperature topic, and using gpio port 4 to talk to a DHT22 sensor Example of sensor connected to 41 | #Raspberry Pi pin 23 it will use the default update time of 300 secons.DHT_PIN = sys.argv[3] Example of sensor connected to Beaglebone 42 | #Black pin P8_11 DHT_PIN = 'P8_11' 43 | #================================================================================================================================================== 44 | # Type of sensor, can be Adafruit_DHT.DHT11, Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302. 45 | DHT_TYPE = Adafruit_DHT.DHT22 46 | 47 | # Example of sensor connected to Raspberry Pi pin 23 48 | DHT_PIN = 4 49 | # Example of sensor connected to Beaglebone Black pin P8_11 50 | #DHT_PIN = 'P8_11' 51 | 52 | 53 | # How long to wait (in seconds) between measurements. 54 | FREQUENCY_SECONDS = 200 55 | 56 | def main(configfile='homie-dht.json'): 57 | Homie = homie.Homie(configfile) 58 | temperatureNode = Homie.Node("temperature","temperature") 59 | humidityNode = Homie.Node("humidity","humidity") 60 | 61 | json_data=open(configfile).read() 62 | data = json.loads(json_data) 63 | FREQUENCY_SECONDS =data["dht"]["frequency"] 64 | DHT_PIN = data["dht"]["pin"] 65 | print('Logging sensor measurements to {0} every {1} seconds.'.format('MQTT', FREQUENCY_SECONDS)) 66 | Homie.setFirmware("dht-temperature","1.0.0") 67 | Homie.setup() 68 | while True: 69 | try: 70 | # Attempt to get sensor reading. 71 | print('Performing read on dht') 72 | humidity, temp = Adafruit_DHT.read(DHT_TYPE, DHT_PIN) 73 | print('After dht read') 74 | 75 | # Skip to the next reading if a valid measurement couldn't be taken. 76 | # This might happen if the CPU is under a lot of load and the sensor 77 | # can't be reliably read (timing is critical to read the sensor). 78 | if humidity is None or temp is None: 79 | time.sleep(2) 80 | print "Nothing received from sensor" 81 | continue 82 | 83 | currentdate = time.strftime('%Y-%m-%d %H:%M:%S') 84 | print('Date Time: {0}'.format(currentdate)) 85 | print('Temperature: {0:0.2f} C'.format(temp)) 86 | print('Humidity: {0:0.2f} %'.format(humidity)) 87 | 88 | # Publish to the MQTT channel 89 | print('Connecting to host') 90 | print("Posting Temperature to homie") 91 | Homie.setNodeProperty(temperatureNode,"degrees",temp,True) 92 | Homie.setNodeProperty(humidityNode,"humidity",humidity,True) 93 | 94 | except Exception,e: 95 | # Error appending data, most likely because credentials are stale. 96 | # Null out the worksheet so a login is performed at the top of the loop. 97 | print('Append error, logging in again: ' + str(e)) 98 | continue 99 | else: 100 | # Wait 30 seconds before continuing 101 | print('Wrote a message tp MQQTT') 102 | time.sleep(FREQUENCY_SECONDS) 103 | 104 | if __name__ == '__main__': 105 | try: 106 | parser= argparse.ArgumentParser(description="Homie Based DHT Reader") 107 | parser.add_argument('-c','--configfile', help='Configuration filename (json)',required=True) 108 | args = parser.parse_args() 109 | main(args.configfile) 110 | except (KeyboardInterrupt, SystemExit): 111 | print "quitting." 112 | 113 | -------------------------------------------------------------------------------- /mqtt.homie.fancontrol.py: -------------------------------------------------------------------------------- 1 | import RPi.GPIO as GPIO 2 | import sys 3 | import time 4 | import json 5 | import homie 6 | import random 7 | import argparse 8 | import logging 9 | 10 | 11 | 12 | 13 | def main(configfile="homie-python.json"): 14 | global fan 15 | global Homie 16 | global switchNode 17 | json_data=open(configfile).read() 18 | data = json.loads(json_data) 19 | fanMouth = data["relay"]["pin"] 20 | logname = data["relay"]["log"] 21 | logging.basicConfig(filename=logname, level=logging.INFO,format='%(asctime)s %(levelname)s %(message)s') 22 | 23 | turnedon = 0 24 | logging.info("Setting up GPIO ports") 25 | GPIO.setwarnings(False) 26 | GPIO.setmode(GPIO.BCM) ## Indicates which pin numbering configuration to use 27 | print("Setting up GPIO ports") 28 | GPIO.setup(fanMouth, GPIO.OUT) 29 | GPIO.output(fanMouth,GPIO.HIGH) 30 | 31 | fan = GPIO.PWM(fanMouth, 100) 32 | logging.info("GPIO ports set up on port %s" % fanMouth) 33 | print("GPIO ports set up on port %s" % fanMouth) 34 | 35 | 36 | fan.start(0) 37 | PAUSE_TIME = 60.02 38 | 39 | logging.info("Starting homie") 40 | print("Starting homie") 41 | Homie = homie.Homie(configfile) 42 | switchNode = Homie.Node("switch","switch") 43 | Homie.setFirmware("fancontrol","1.0.0") 44 | Homie.subscribe(switchNode, "on", switchOnHandler) 45 | logging.info("Running setup") 46 | print("Running setup") 47 | Homie.setup() 48 | print Homie 49 | print switchNode 50 | 51 | while True: 52 | try: 53 | time.sleep(1) 54 | except Exception,e: 55 | # Error appending data, most likely because credentials are stale. 56 | # Null out the worksheet so a login is performed at the top of the lo 57 | logging.error("Error in mqtt loop") 58 | print('Append error, logging in again: ' + str(e)) 59 | continue 60 | 61 | 62 | except KeyboardInterrupt: 63 | print("error") 64 | GPIO.cleanup() 65 | exit(0) 66 | 67 | # The callback for when a PUBLISH message is received from the server. 68 | def switchOnHandler(mqttc, obj, msg): 69 | global fan 70 | global Homie 71 | global switchNode 72 | print('topic') 73 | logging.info('Topic: ' + msg.topic+' Message: '+str(msg.payload)) 74 | print('Topic: ' + msg.topic+' Message: '+str(msg.payload)) 75 | if msg.payload == "1" or msg.payload == "true" or msg.payload == "ON" or msg.payload == "on": 76 | print 'turning fan on' 77 | logging.info("Turning Fan on") 78 | fan.ChangeDutyCycle(100) 79 | Homie.setNodeProperty(switchNode,"on" "false", True) 80 | else: 81 | logging.info("Turning fan off") 82 | print 'turning fan off' 83 | fan.ChangeDutyCycle(0) 84 | Homie.setNodeProperty(switchNode, "on" "false", True) 85 | 86 | 87 | 88 | if __name__ == '__main__': 89 | try: 90 | parser= argparse.ArgumentParser(description="Homie Based Fan Control") 91 | parser.add_argument('-c','--configfile', help='Configuration filename (json)',required=True) 92 | args = parser.parse_args() 93 | main(args.configfile) 94 | except (KeyboardInterrupt, SystemExit): 95 | logging.info("Quitting.") 96 | --------------------------------------------------------------------------------