Thanks for the reply. I thought that I would be in trouble trying to interface the Makerfabs gateway to H/A. Could you direct me to what gateway I should be looking at to get this project up and running? Thanks for all the good work you have done on this.
Here is a link to OpenMQTT’s page on devices that can be used as Gateways in general, but for their LoRa gateways, you’ll have to search the page for LoRa capabilities. Usually a Heltec or a TTGO board is compatible.
Would the Heltech WiFi LoRa 32(V3) or Lilygo LoRa32 V2.1_1.6 be suitable? I also looked at the Heltech Wireless Gateway which transmits wireless and bluetooth simultaneously. Which would you suggest to buy. Just want to make sure that I purchase the right gateway.Thanks.
I would recommend asking on the OMG Community Forum. The other part to consider as well is whether there is a pre-compiled binary available or if you have to build the binary yourself.
I am having issue with the data being shown in HA. Running the v3 soil monitors with a Lilygo gateway, both set to 915mhz. The soil sensors are transmitting correctly and being received by the gateway. I have MQTT Explorer setup and the data is showing as being received correctly in that part. The HA MQTT logs are also recording that the data is being correctly received there also. Have OMG set up as a custom component and when I view the Logbook for this component all that is being shown is startup detail and any manual changes I have made. No data is being pushed through to this HACS component. An MQTT sensor that I have set up using syntax from Mask (2/2023) creates a sensor but has a status of unknown. I have worked my way through the issues documented by others in this forum. It seems that my problem is similar to that described by thebang2 in 7/2022 above but am unsure what I need to do in respect of changes recommended by kamaradclimber.
Any assistance would be appreciated. Thanks.
Finally succeeded in getting this working. The end issue in my case was making the following changes to the syntax in HA from coding in the config file from contributor thebang2 7/2022, viz
FROM
value_template: >-
{% if (value_json.message|from_json).node_id == “ID846758” %}
{{ (value_json.message|from_json).hum }}
{% else %}
{{ is_state_attr(“sensor.soil01_humidity”) | round(2) }}
{% endif %}
TO
value_template: >-
{% if (value|from_json).node_id == “ID011422” %}
{{ (value|from_json).hum | round(1)}}
{% else %}
{{ is_state_attr(“sensor.Soil Hum ID011422”) | round(1) }}
{% endif %}
Hope that this will help somebody.
Would you mind please posting your yaml properly. Thanks.
Would love to hear what values you used for dry/wet? I’ve tested around a lot but I’m still unhappy, it seems like I always measure the soil ‘too wet’.
600 → minimum value that corresponds to 100% humidity
750 → maximum value that corresponds to 0% humidity
I spent most of today getting this to work. As you might have noticed, all the examples online use RadioLib but that library is very big and doesnt fit in to the ATmega328P’s flash, so i replaced it with LoRa.h. I also found the temperature and humidity sensors were all over the place, so i just disabled them. When configured to connect to OpenMQTTGateway, autodiscovery in Home Assistant works, although the “connected via” device is “unknown”. Note that sometimes it takes 3-5 minutes for the gateway to create the discovery messages on the broker.
and here’s a sensor:
Anywhay, here’s my code:
#include <SPI.h>
#include <Wire.h>
#include <LoRa.h>
#include <ArduinoJson.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
// #include "I2C_AHT10.h"
String node_id = String("ID") + "011786";
#define DEVICE_NAME "SOIL_V3"
#define MANUFACTURER "MAKERFABS"
#define VERSION "1.0"
#define MOISTURE_AIR_VALUE 855 // Raw ADC reading in air (dry)
#define MOISTURE_WATER_VALUE 530 // Raw ADC reading in water (wet)
/**
* Sleep cycle timing calculations
*
* The watchdog timer is set with WDP3 | WDP0 which gives an 8-second interval
* Each interrupt increases count by 1
*
* Time = count * 8 seconds
*
* Current setting:
* SLEEP_CYCLE = 450
* 450 * 8 seconds = 3600 seconds = 1 hour
*
* Other common intervals:
* 6 hours = 2700 cycles (2700 * 8 = 21600 seconds)
* 12 hours = 5400 cycles (5400 * 8 = 43200 seconds)
* 24 hours = 10800 cycles (10800 * 8 = 86400 seconds)
*
* For testing:
* 20 seconds ≈ 1 cycle (1 * 8 = 8 seconds)
*/
#define SLEEP_CYCLE 450
// Lora set
// Set Lora frequency
// #define FREQUENCY 433E6 //434.0
#define FREQUENCY 868E6 // 868.3
// #define FREQUENCY 915E6 // 915.0
#define BANDWIDTH 125.0
#define SPREADING_FACTOR 9
#define CODING_RATE 7
#define OUTPUT_POWER 10
#define PREAMBLE_LEN 8
#define GAIN 0
#define DIO0 2
#define DIO1 6
#define LORA_RST 4
#define LORA_CS 10
#define SPI_MOSI 11
#define SPI_MISO 12
#define SPI_SCK 13
#define VOLTAGE_PIN A3
#define PWM_OUT_PIN 9
#define SENSOR_POWER_PIN 5
#define ADC_PIN A2
#define DEBUG_OUT_ENABLE 1
// AHT10 humiditySensor;
bool readSensorStatus = false;
int sensorValue = 0; // variable to store the value coming from the sensor
int batValue = 0; // the voltage of battery
int count = 0;
int ADC_O_1; // ADC Output First 8 bits
int ADC_O_2; // ADC Output Next 2 bits
int16_t packetnum = 0; // packet counter, we increment per xmission
float temperature = 0.0;
float humidity = 0.0;
// bool AHT_init()
// {
// bool ret = false;
// Wire.begin();
// if (humiditySensor.begin() == false)
// {
// #if DEBUG_OUT_ENABLE
// Serial.println("AHT10 not detected. Please check wiring. Freezing.");
// #endif
// }
// if (humiditySensor.available() == true)
// {
// temperature = humiditySensor.getTemperature();
// humidity = humiditySensor.getHumidity();
// ret = true;
// }
// if (isnan(humidity) || isnan(temperature))
// {
// #if DEBUG_OUT_ENABLE
// Serial.println(F("Failed to read from AHT sensor!"));
// #endif
// }
// return ret;
// }
void Lora_init()
{
LoRa.setPins(LORA_CS, LORA_RST, DIO0);
LoRa.setSpreadingFactor(7);
LoRa.setCodingRate4(5);
LoRa.setPreambleLength(8);
LoRa.setSyncWord(0x12);
LoRa.setSignalBandwidth(125E3);
int state = LoRa.begin(FREQUENCY);
if (state == 1)
{
#if DEBUG_OUT_ENABLE
Serial.println(F("success!"));
#endif
}
else
{
#if DEBUG_OUT_ENABLE
Serial.print(F("failed, code "));
Serial.println(state);
#endif
}
}
void setup()
{
#if DEBUG_OUT_ENABLE
Serial.begin(115200);
Serial.println("Soil start.");
#endif
delay(100);
pinMode(PWM_OUT_PIN, OUTPUT);
TCCR1A = bit(COM1A0); // toggle OC1A on Compare Match
TCCR1B = bit(WGM12) | bit(CS10); // CTC, scale to clock
OCR1A = 1;
pinMode(LORA_RST, OUTPUT);
digitalWrite(LORA_RST, HIGH);
delay(100);
pinMode(SENSOR_POWER_PIN, OUTPUT);
digitalWrite(SENSOR_POWER_PIN, HIGH); // Sensor power on
delay(100);
Lora_init();
// Wire.begin();
// if (humiditySensor.begin() == false)
// {
// #if DEBUG_OUT_ENABLE
// Serial.println("AHT10 not detected. Please check wiring. Freezing.");
// #endif
// }
// #if DEBUG_OUT_ENABLE
// else
// Serial.println("AHT10 acknowledged.");
// #endif
do_some_work();
#if DEBUG_OUT_ENABLE
Serial.println("[Set]Sleep Mode Set");
#endif
low_power_set();
}
void loop()
{
wdt_disable();
if (count > SLEEP_CYCLE) //(7+1) x 8S 450
{
#if DEBUG_OUT_ENABLE
Serial.println("Code start>>");
#endif
do_some_work();
all_pins_low();
#if DEBUG_OUT_ENABLE
Serial.println("Code end<<");
#endif
count = 0;
}
low_power_set();
}
ISR(WDT_vect)
{
#if DEBUG_OUT_ENABLE
Serial.print("[Watch dog]");
Serial.println(count);
#endif
delay(100);
count++;
// wdt_reset();
wdt_disable(); // disable watchdog
}
void low_power_set()
{
all_pins_low();
delay(10);
ADCSRA = 0;
sleep_enable();
watchdog_init();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
delay(10);
noInterrupts();
sleep_enable();
MCUCR = bit(BODS) | bit(BODSE);
MCUCR = bit(BODS);
interrupts();
sleep_cpu();
sleep_disable();
}
void watchdog_init()
{
MCUSR = 0;
WDTCSR = bit(WDCE) | bit(WDE);
WDTCSR = bit(WDIE) | bit(WDP3) | bit(WDP0); // set WDIE, and 8 seconds delay
wdt_reset(); // pat the dog
}
void do_some_work()
{
digitalWrite(SENSOR_POWER_PIN, HIGH); // Sensor/RF95 power on
digitalWrite(LORA_RST, HIGH);
delay(5);
pinMode(PWM_OUT_PIN, OUTPUT); // digitalWrite(PWM_OUT_PIN, LOW);
TCCR1A = bit(COM1A0); // toggle OC1A on Compare Match
TCCR1B = bit(WGM12) | bit(CS10); // CTC, scale to clock
OCR1A = 1; // compare A register value (5000 * clock speed / 1024).When OCR1A == 1, PWM is 2MHz
Lora_init();
delay(50);
ADMUX = _BV(REFS0) | _BV(MUX1);
ADCSRA = _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0);
delay(50);
for (int i = 0; i < 3; i++)
{
ADCSRA |= (1 << ADSC);
delay(10);
if ((ADCSRA & 0x40) == 0)
{
ADC_O_1 = ADCL;
ADC_O_2 = ADCH;
sensorValue = (ADC_O_2 << 8) + ADC_O_1;
ADCSRA |= 0x40;
#if DEBUG_OUT_ENABLE
Serial.print("ADC:");
Serial.println(sensorValue);
#endif
// if (readSensorStatus == false)
// readSensorStatus = AHT_init();
}
ADCSRA |= (1 << ADIF); // reset as required
delay(50);
}
ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX1) | _BV(MUX0);
delay(50);
for (int i = 0; i < 3; i++)
{
ADCSRA |= (1 << ADSC);
delay(10);
if ((ADCSRA & 0x40) == 0)
{
ADC_O_1 = ADCL;
ADC_O_2 = ADCH;
batValue = (ADC_O_2 << 8) + ADC_O_1;
ADCSRA |= 0x40;
#if DEBUG_OUT_ENABLE
Serial.print("BAT:");
Serial.println(batValue);
float bat = (float)batValue * 3.3;
bat = bat / 1024.0;
Serial.print(bat);
Serial.print("V");
#endif
}
ADCSRA |= (1 << ADIF); // reset as required
delay(50);
}
send_sensor_data();
delay(1000);
LoRa.sleep();
packetnum++;
readSensorStatus = false;
digitalWrite(SENSOR_POWER_PIN, LOW); // Sensor/RF95 power off
delay(100);
}
void all_pins_low()
{
pinMode(PWM_OUT_PIN, INPUT);
pinMode(A4, INPUT_PULLUP);
pinMode(A5, INPUT_PULLUP);
delay(50);
}
void send_sensor_data()
{
JsonDocument payload;
int moisture_percent = 0;
if (MOISTURE_AIR_VALUE != MOISTURE_WATER_VALUE)
{
moisture_percent = map(sensorValue,
MOISTURE_AIR_VALUE,
MOISTURE_WATER_VALUE,
0, 100);
moisture_percent = constrain(moisture_percent, 0, 100);
}
float voltage = (float)batValue * 3.3 / 1024.0;
float battery_percent = constrain(map(voltage * 100, 250, 330, 0, 100), 0, 100);
auto device = payload["device"].to<JsonObject>();
device["identifiers"] = node_id;
device["name"] = String("Soil Sensor ") + node_id;
device["model"] = DEVICE_NAME;
device["manufacturer"] = MANUFACTURER;
device["sw_version"] = VERSION;
payload["nodeId"] = node_id;
payload["id"] = node_id;
payload["moi"] = moisture_percent;
payload["batt"] = battery_percent;
#if DEBUG_OUT_ENABLE
serializeJson(payload, Serial);
Serial.println();
#endif
if (!LoRa.beginPacket())
{
return;
}
if (payload.overflowed())
{
#if DEBUG_OUT_ENABLE
Serial.println("JSON overflow");
#endif
}
serializeJson(payload, LoRa);
if (!LoRa.endPacket())
{
#if DEBUG_OUT_ENABLE
Serial.println("LoRa packet send failed");
#endif
};
}
To flash, you need to hold down the rest button, and then when you see something like this, release it:
Using manually specified: /dev/cu.usbserial-0267D68A
Uploading .pio/build/ATmega328P/firmware.hex
For the OpenMQTTGateway, i’m using the Lilygo LoRa32 v2.1_1.6 but flashed with the ttgo-lora32-v21
prebuilt image v1.8. There are no other changes.
hope this helps.
I just calibrated it by measuring it dry, and then again when dunked in a glass of water and used that as 0% and 100%.