So I would like to add a PH sensor (atlas scientific) over the I2C bus on a Raspberry PI for a hydroponics project. So I pretty much totally newbie here with Cayenne and wondering how I should start trying to write a custom MQTT? driver for it. Hopefully I could make up a python library but not sure how to even just start with it. I seen a few things that might be close to what I want but a lot of stuff here is for Ardinio and not Raspberry Pi applications.
Try to look at this project, working with Raspberry Pi and MQTT.
well after figuring out if I put my code in the example directory of the API library files I was able to play with it…
Here is what I mashed together from the atlas example and the cayenne python MQTT example. Its just a start but at least it seems to be working so far…
#!/usr/bin/env python import cayenne.client import io # used to create file streams import fcntl # used to access I2C parameters like addresses import time import string # helps parse strings class atlas_i2c: long_timeout = 3 # the timeout needed to query readings and calibrations short_timeout = .5 # timeout for regular commands default_bus = 1 # the default bus for I2C on the newer Raspberry Pis, certain older boards use bus 0 default_address = 99 # the default address for the pH sensor def __init__(self, address = default_address, bus = default_bus): # open two file streams, one for reading and one for writing # the specific I2C channel is selected with bus # it is usually 1, except for older revisions where its 0 # wb and rb indicate binary read and write self.file_read = io.open("/dev/i2c-"+str(bus), "rb", buffering = 0) self.file_write = io.open("/dev/i2c-"+str(bus), "wb", buffering = 0) # initializes I2C to either a user specified or default address self.set_i2c_address(address) def set_i2c_address(self, addr): # set the I2C communications to the slave specified by the address # The commands for I2C dev using the ioctl functions are specified in # the i2c-dev.h file from i2c-tools I2C_SLAVE = 0x703 fcntl.ioctl(self.file_read, I2C_SLAVE, addr) fcntl.ioctl(self.file_write, I2C_SLAVE, addr) def write(self, string): # appends the null character and sends the string over I2C string += "\00" self.file_write.write(string) def read(self, num_of_bytes = 31): # reads a specified number of bytes from I2C, then parses and displays the result res = self.file_read.read(num_of_bytes) # read from the board response = filter(lambda x: x != '\x00', res) # remove the null characters to get the response if(ord(response) == 1): # if the response isnt an error char_list = map(lambda x: chr(ord(x) & ~0x80), list(response[1:])) # change MSB to 0 for all received characters except the first and get a list of characters # NOTE: having to change the MSB to 0 is a glitch in the raspberry pi, and you shouldn't have to do this! return "Command succeeded " + ''.join(char_list) # convert the char list to a string and returns it else: return "Error " + str(ord(response)) def query(self, string): # write a command to the board, wait the correct timeout, and read the response self.write(string) # the read and calibration commands require a longer timeout if((string.upper().startswith("R")) or (string.upper().startswith("CAL"))): time.sleep(self.long_timeout) elif((string.upper().startswith("SLEEP"))): return "sleep mode" else: time.sleep(self.short_timeout) return self.read() def close(self): self.file_read.close() self.file_write.close() def main(): device = atlas_i2c() # creates the I2C port object, specify the address or bus if necessary # Cayenne authentication info. This should be obtained from the Cayenne Dashboard. MQTT_USERNAME = "" MQTT_PASSWORD = "" MQTT_CLIENT_ID = "" # The callback for when a message is received from Cayenne. def on_message(message): print("message received: " + str(message)) # If there is an error processing the message return an error string, otherwise return nothing. client = cayenne.client.CayenneMQTTClient() client.on_message = on_message client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID) i=0 timestamp = 0 output = "0.00" phvalue = 7 while True: client.loop() if (time.time() > timestamp + 10): try: output = device.query("R") print(output); except IOError: print("Query failed") phvalue = float(string.split(output, ' ')) client.virtualWrite(1, phvalue, dataType='PH', dataUnit='PH') timestamp = time.time() i = i+1 if __name__ == '__main__': main()
When you share the code, remember to delete your MQTT username, password and clientID.
MQTT_USERNAME = "username" MQTT_PASSWORD = "password" MQTT_CLIENT_ID = "clientID"
I already have aph probe would something like this work?
yes, connect the pH sensor to the pi and get reading from it by following this https://myhydropi.com/connecting-a-ph-sensor-to-a-raspberry-pi and then use cayenne MQTT python library to send data to cayenne https://github.com/myDevicesIoT/Cayenne-MQTT-Python
thank you, the code worked perfect. I had been fighting with trying to get/make code to use the ADS1115 which I am still working on for some other analog sensors but this worked perfect to at least get me the ph sensor working fine.
I’m hoping that maybe this winter I get back into working on this project. Glad you figured out what it was you were trying to get work.
yea it just sucks that the pia2d and pwm do not work anymore I want to add some pumps with a pwm module to add ph+ and -.