Import data from sensor into node-red

Hey people!

I’m doing a uni assignment on Iot, and we are doing a soil moisture system with a water pump. One stipulation is that we need to use Node-Red.

List of components

*MCP3008 8-channel ADC
Raspberry Pi 4

*Dfrobot Gravity: Analog Waterproof Capacitive Soil Moisture Sensor

*Piico Dev oLED

*Piico Dev adapter for raspberry pi

*Dfrobot: Amphibious Horizontal Submersible Pump

*Using Mac and controlling raspberry pi through the terminal.

Okay. Im a full rookie here… Apart from connecting a dht22 humidity this is my first project…. Here’s where I’m at:

Installed MCP3XXX library and done this…. sudo pip3 install adafruit-circuitpython-mcp3xxx As per everything on this thread Python & CircuitPython | MCP3008 - 8-Channel 10-Bit ADC With SPI Interface | Adafruit Learning System

Set up a mosquito mqtt broker and
node red is connected (check screen shots)`

Heres the code that has been stored
in ` “/home/pi/./code.py”

# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn

# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)

# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D5)

# create the mcp object
mcp = MCP.MCP3008(spi, cs)

# create an analog input channel on pin 0
chan = AnalogIn(mcp, MCP.P0)

print("Raw ADC Value: ", chan.value)
print("ADC Voltage: " + str(chan.voltage) + "V")

Now I run this
code: ` python3 ./code.py and I get data coming in from the sensor. And it does change when I put the sensor in water… so that seems to be working (Look at screenshot).

So what I need is to import this into node-red I’m assuming we need to use an “mqtt in” node, but I just can’t figure it out… I’ve watched probably 40 different YouTube videos, and it looks so easy but nothing seems to work.

When I use a “mqtt in”node I get nothing coming through
the debugger… It shows it is connect but no error msg or data. (check
screenshots) `



Is there a
different way to import the data coming in from the raspberry pi, or is there
something I’m missing?`

I think I will need to calibrate the sensor and somehow set the parameters to interpret the data as come sort of high, medium, low soil moisture level. Not sure if i can do this in Node-Red or do I have to do this in Terminal.

And I haven’t even
attempted to connect the water pump and oLED ,to display if the soil is wet or
not, yet. So many more questions will
probably be on the way haha`

Can some legend out
there same me!!`

Hi Jack,

Yes, the node-red requirement definitely puts a damper on things. How is your python code publishing to MQTT?

If MQTT proves too hard, you could try writing to a JSON file with Python, and have node-red read that.

hey James,

yes I understand that now, ive updated the code…
I tried changing the port number to 1886 because, according to chatgpt, there might have been an issue with conflicting port usage. But now the mqtt want connect in node-red and I get this error in my terminal window but not it the debug in node-red…


import os
import time
import paho.mqtt.client as mqtt
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as MCP
from adafruit_mcp3xxx.analog_in import AnalogIn

# create the spi bus
spi = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)

# create the cs (chip select)
cs = digitalio.DigitalInOut(board.D22)

# create the mcp object
mcp = MCP.MCP3008(spi, cs)

# create an analog input channel on pin 0
chanel = AnalogIn(mcp, MCP.P0)

# Set up MQTT client
mqtt_client = mqtt.Client()
mqtt_client.connect("192.168.0.100", 1886)  # Use the correct port (usually 1883)

# Start the MQTT client's loop
mqtt_client.loop_start()

while True:
    # Read the soil moisture value
    soil_moisture = chanel.value  # You should replace this with your actual value
    # Print the value of soil_moisture
    print('Soil Moisture:', soil_moisture)  
    print('Raw ADC Value: ', soil_moisture)
    print('ADC Voltage: ' + str(chanel.voltage) + 'V')

    # Publish the soil moisture value to an MQTT topic
    mqtt_client.publish("soil_moisture", soil_moisture)

    time.sleep(0.5)

Hi Jack,
Can I suggest using the free HiveMQ broker to send your data to and then subscribe using NodeRED?
I found it quite easy to do it this way and I have very little knowledge when it comes to this.
Here is my code and a screenshot. I have an on board camera and I get water level from an Arduino over USB. Each have their own message and own subscription.
Adam

Here is my code

import time
import serial
import paho.mqtt.client as paho
from paho import mqtt
import base64
from io import BytesIO
from picamera import PiCamera
import datetime
#import subprocess # Import the subprocess module

Adjustable publish times

WATER_LEVEL_CURRENT_PUBLISH_INTERVAL = 60 # seconds
WATER_LEVEL_PHOTO_PUBLISH_INTERVAL = 60 # seconds

MQTT Callbacks and setup

def on_connect(client, userdata, flags, rc, properties=None):
print(“CONNACK received with code %s.” % rc)

def on_publish(client, userdata, mid, properties=None):
print("mid: " + str(mid))

def on_subscribe(client, userdata, mid, granted_qos, properties=None):
print("Subscribed: " + str(mid) + " " + str(granted_qos))

def on_message(client, userdata, msg):
print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))

def get_current_timestamp():
return datetime.datetime.now().strftime(‘%d/%m/%Y %H:%M:%S’)
#def get_core_voltage():

try:

   # voltage = subprocess.check_output(['vcgencmd', 'measure_volts', 'core']).decode('utf-8')
   # voltage = voltage.split('=')[1].replace('V', '').strip()

return voltage

except:

return “Unknown”

client = paho.Client(client_id=“”, userdata=None, protocol=paho.MQTTv5)
client.on_connect = on_connect

Enable TLS for secure connection

client.tls_set(tls_version=mqtt.client.ssl.PROTOCOL_TLS)

Set username and password

USERNAME = “xxxxxxxxxx”
PASSWORD = “xxxxxxxxxx”
client.username_pw_set(USERNAME, PASSWORD)

Connect to the MQTT broker

BROKER_URL = “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.s1.eu.hivemq.cloud”
PORT = 8883
client.connect(BROKER_URL, PORT)

client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_publish = on_publish

Subscribe to the WaterLevel/Current and WaterLevel/Photo topics

client.subscribe(“WaterLevel/Current”, qos=1)
client.subscribe(“WaterLevel/Photo”, qos=1)

Function to read and average Arduino data

def read_and_average_arduino_data(port=‘/dev/ttyACM0’, baudrate=57600, interval=60):
ser = serial.Serial(port, baudrate)
time.sleep(2)

readings = []
start_time = time.time()

try:
    while time.time() - start_time < interval:
        raw_line = ser.readline()
        try:
            line = raw_line.decode('utf-8').strip()
        except UnicodeDecodeError:
            continue  # Skip this line if it can't be decoded

        try:
            distance_cm = float(line.split('=')[-1].replace('cm', '').strip())
            readings.append(distance_cm)
        except ValueError:
            pass

    if readings:
        avg_distance_cm = sum(readings) / len(readings)
        avg_distance_m = avg_distance_cm / 100
        return f"{avg_distance_m:.3f}"
    else:
        return "No valid readings"

finally:
    ser.close()

Function to capture a photo and return it as a base64 encoded string

def capture_photo():
with PiCamera() as camera:
camera.resolution = (1280, 720) # Set resolution to 360p
stream = BytesIO()
camera.capture(stream, format=‘jpeg’, quality=25) # Reduce JPEG quality
stream.seek(0)
return base64.b64encode(stream.read()).decode(‘utf-8’)

Publish a message to the MQTT broker

def publish_message(topic, payload, qos=1):
if topic == “WaterLevel/Current”:
timestamp = get_current_timestamp()
payload = f"{payload}; {timestamp};"
client.publish(topic, payload=payload, qos=qos)

Start the MQTT network loop in the background

client.loop_start()

try:
while True:
# Get the average water level from the Arduino
water_level = read_and_average_arduino_data()

    # Get the core voltage
   # core_voltage = get_core_voltage()
    
    # Publish the water level to the MQTT broker
    publish_message("WaterLevel/Current", water_level)

    # Capture a photo and get its base64 encoded string
    photo_base64 = capture_photo()

 # Publish the photo to the MQTT broker
    publish_message("WaterLevel/Photo", photo_base64)

    # Wait for the next interval
    time.sleep(WATER_LEVEL_CURRENT_PUBLISH_INTERVAL)

except KeyboardInterrupt:
print(“\nInterrupted by user.”)

finally:
# Stop the MQTT network loop and disconnect
client.loop_stop()
client.disconnect()
print(“MQTT client disconnected.”)

For some reason it didn’t paste properly, copy the whole lot, not just the yellow area.

@jack253791
I put (most of) your code into Python and Node-Red and it worked OK.
My mosquitto server is on 1883 so used that, but I think you are 99% there?

Edit> I mean your MQTT code that is :slight_smile: