from umqtt.simple import MQTTClient from machine import Pin,I2C import network import time import ssd1306 from cayenne import __version__ import logging import sys pinScl = 5 #ESP8266 GPIO5 (D1) pinSda = 4 #ESP8266 GPIO4 (D2) addrOled = 60 #0x3c hSize = 48 # Hauteur ecran en pixels | display height in pixels wSize = 64 # Largeur ecran en pixels | display width in pixels oledIsConnected = False #wifi setting SSID="SFR_A0F0_EXT" #insert your wifi ssid PASSWORD="osto7rawayristaxtris" #insert your wifi password CLIENT_ID = "YourWeMosD1ClientID" #insert your client ID username='YourCayenneUsername' #insert your MQTT username password='YourCayennePassword' #insert your MQTT password # LOG LOG_NAME = "CayenneMQTTClient" # Data types TYPE_BAROMETRIC_PRESSURE = "bp" # Barometric pressure TYPE_BATTERY = "batt" # Battery TYPE_LUMINOSITY = "lum" # Luminosity TYPE_PROXIMITY = "prox" # Proximity TYPE_RELATIVE_HUMIDITY = "rel_hum" # Relative Humidity TYPE_TEMPERATURE = "temp" # Temperature TYPE_VOLTAGE = "voltage" # Voltage # Unit types UNIT_UNDEFINED = "null" UNIT_PASCAL = "pa" # Pascal UNIT_HECTOPASCAL = "hpa" # Hectopascal UNIT_PERCENT = "p" # % (0 to 100) UNIT_RATIO = "r" # Ratio UNIT_VOLTS = "v" # Volts UNIT_LUX = "lux" # Lux UNIT_CENTIMETER = "cm" # Centimeter UNIT_METER = "m" # Meter UNIT_DIGITAL = "d" # Digital (0/1) UNIT_FAHRENHEIT = "f" # Fahrenheit UNIT_CELSIUS = "c" # Celsius UNIT_KELVIN = "k" # Kelvin UNIT_MILLIVOLTS = "mv" # Millivolts # Topics COMMAND_TOPIC = "cmd" DATA_TOPIC = "data" RESPONSE_TOPIC = "response" SSID="YourWiFiSSID" #insert your wifi ssid PASSWORD="YourWiFiPassword" #insert your wifi password class CayenneMessage: """ This is a class that describes an incoming Cayenne message. It is passed to the on_message callback as the message parameter. Members: client_id : String. Client ID that the message was published on. topic : String. Topic that the message was published on. channel : Int. Channel that the message was published on. msg_id : String. The message ID. value : String. The message value. """ def __init__(self, topic,payload): topic_tokens = topic.decode().split('/') self.client_id = topic_tokens[3] self.topic = topic_tokens[4] self.channel = int(topic_tokens[5]) payload_tokens = payload.decode().split(',') self.msg_id = payload_tokens[0] self.value = payload_tokens[1] def __repr__(self): return str(self.__dict__) class CayenneMQTTClient: """Cayenne MQTT Client class. This is the main client class for connecting to Cayenne and sending and receiving data. Standard usage: * Set on_message callback, if you are receiving data. * Connect to Cayenne using the begin() function. * Call loop() at intervals (or loop_forever() once) to perform message processing. * Send data to Cayenne using write functions: virtualWrite(), celsiusWrite(), etc. * Receive and process data from Cayenne in the on_message callback. The on_message callback can be used by creating a function and assigning it to CayenneMQTTClient.on_message member. The callback function should have the following signature: on_message(message) The message variable passed to the callback is an instance of the CayenneMessage class. """ def __init__(self): # init ic2 object i2c = I2C(scl=Pin(pinScl), sda=Pin(pinSda)) #ESP8266 5/4 # Scan the i2c bus and verify if the OLED sceen is connected print('Scan i2c bus...') self.devices = i2c.scan() if len(self.devices) == 0: print("No i2c device !") else: for self.device in self.devices: print("OLED found") if self.device == addrOled: self.oled = ssd1306.SSD1306_I2C(wSize, hSize, i2c, addrOled) self.oledIsConnected = True self.client = None self.rootTopic = "" self.connected = False self.on_message = None """Initializes the client and connects to Cayenne. ssid is WiFi ssid wifiPassword username is the Cayenne username. password is the Cayenne password. clientID is the Cayennne client ID for the device. hostname is the MQTT broker hostname. port is the MQTT broker port. Use port 8883 for secure connections. logname is the name of the users log if they want the client to log to their logging setup. loglevel is the logging level that will be applied to logs. """ def begin(self, username, password, clientid, ssid=SSID, wifiPassword=PASSWORD, hostname='mqtt.mydevices.com', port=1883, logname=LOG_NAME, loglevel=logging.WARNING): self.rootTopic = "v1/%s/things/%s" % (username, clientid) print("root topic: %s"%self.rootTopic); global wlan wlan=network.WLAN(network.STA_IF) wlan.active(True) wlan.disconnect() # try to connect to wlan print('connecting to network...') if self.oledIsConnected: self.oled.fill(0) self.oled.text("Connect",0,0) self.oled.text("to WiFi",0,10) self.oled.show() print("Trying to connect to %s"%ssid) wlan.connect(ssid,wifiPassword) while(wlan.ifconfig()[0]=='0.0.0.0'): time.sleep(1) print('network config:', wlan.ifconfig()) if self.oledIsConnected: self.ipAddress = wlan.ifconfig()[0] self.oled.fill(0) self.oled.text("IP:",0,0) self.oled.text(self.ipAddress[0:8],0,10) self.oled.text(self.ipAddress[8:],0,20) self.oled.show() print("Connecting to %s"%hostname) self.client = MQTTClient(clientid, hostname,0,username,password) self.client.connect() self.connected=True self.log = logging.getLogger(logname) # if logname == LOG_NAME: # logging.basicConfig(stream=sys.stdout, format='%(message)s', level=loglevel) self.log.info("Connecting to %s:%s"%(hostname, port)) if self.oledIsConnected: self.oled.text("Cayenne",0,30) self.oled.text("MQTT ok",0,40) self.oled.show() # subscribe to the cmd topic command_topic = self.getCommandTopic() self.client.set_callback(self.client_on_message) self.log.info("SUB %s"%command_topic) self.client.subscribe(command_topic) def client_on_message(self,topic,payload): # The callback for when a PUBLISH message is received from the server. self.log.info("RCV %s %s"%(topic, payload)) self.message=CayenneMessage(topic,payload) # If there was no error, we send the new channel state, which should be the command value we received. self.virtualWrite(self.message.channel, self.message.value) # Send a response showing we received the message, along with any error from processing it. self.responseWrite(self.message.msg_id, None) if self.on_message: print("callback with %s %s"%(topic,payload)) self.msg=(topic,payload) self.on_message(self.msg) else: print("No callback defined") def getDataTopic(self, channel): """Get the data topic string. channel is the channel to send data to. """ return "%s/%s/%s" % (self.rootTopic, DATA_TOPIC, channel) def getCommandTopic(self): """Get the command topic string.""" return "%s/%s/+" % (self.rootTopic, COMMAND_TOPIC) def getResponseTopic(self): """Get the response topic string.""" return "%s/%s" % (self.rootTopic, RESPONSE_TOPIC) def virtualWrite(self, channel, value, dataType="", dataUnit=""): """Send data to Cayenne. channel is the Cayenne channel to use. value is the data value to send. dataType is the type of data. dataUnit is the unit of the data. """ if (self.connected): topic = self.getDataTopic(channel) if dataType: payload = "%s,%s=%s" % (dataType, dataUnit, value) else: payload = value self.mqttPublish(topic, payload) def responseWrite(self, msg_id, error_message): """Send a command response to Cayenne. This should be sent when a command message has been received. msg_id is the ID of the message received. error_message is the error message to send. This should be set to None if there is no error. """ if (self.connected): topic = self.getResponseTopic() if error_message: payload = "error,%s=%s" % (msg_id, error_message) else: payload = "ok,%s" % (msg_id) self.mqttPublish(topic, payload) def celsiusWrite(self, channel, value): """Send a Celsius value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_TEMPERATURE, UNIT_CELSIUS) def fahrenheitWrite(self, channel, value): """Send a Fahrenheit value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_TEMPERATURE, UNIT_FAHRENHEIT) def kelvinWrite(self, channel, value): """Send a kelvin value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_TEMPERATURE, UNIT_KELVIN) def luxWrite(self, channel, value): """Send a lux value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_LUMINOSITY, UNIT_LUX) def pascalWrite(self, channel, value): """Send a pascal value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_BAROMETRIC_PRESSURE, UNIT_PASCAL) def hectoPascalWrite(self, channel, value): """Send a hectopascal value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_BAROMETRIC_PRESSURE, UNIT_HECTOPASCAL) def VoltageWrite(self, channel, value): """Send a voltage value to Cayenne. channel is the Cayenne channel to use. value is the data value to send. """ self.virtualWrite(channel, value, TYPE_VOLTAGE, UNIT_MILLIVOLTS) def mqttPublish(self, topic, payload): """Publish a payload to a topic topic is the topic string. payload is the payload data. """ self.log.info("PUB %s %s" % (topic, payload)) self.client.publish(topic, payload) def getClient(self): return self.client def loop(self): """Process Cayenne messages. This should be called regularly to ensure Cayenne messages are sent and received. To be implemented later """ self.client.check_msg() return; def loop_forever(self): """Process Cayenne messages in a blocking loop that runs forever.""" while True: self.client.wait_msg()