2025-07-15 22:28:23 +02:00
|
|
|
/* Copyright (C) 2025 Ricardo Guzman - CA2RXU
|
|
|
|
|
*
|
|
|
|
|
* This file is part of LoRa APRS iGate.
|
|
|
|
|
*
|
|
|
|
|
* LoRa APRS iGate is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* LoRa APRS iGate is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-02-24 20:17:01 +01:00
|
|
|
#include <TinyGPS++.h>
|
2025-05-17 17:43:54 +02:00
|
|
|
#ifdef LIGHTGATEWAY_PLUS_1_0
|
|
|
|
|
#include "Adafruit_SHTC3.h"
|
|
|
|
|
#endif
|
2023-06-18 00:28:40 +02:00
|
|
|
#include "configuration.h"
|
2025-02-24 20:17:01 +01:00
|
|
|
#include "board_pinout.h"
|
2024-10-05 13:48:08 +02:00
|
|
|
#include "wx_utils.h"
|
2023-06-18 00:28:40 +02:00
|
|
|
#include "display.h"
|
|
|
|
|
|
2024-10-05 13:48:08 +02:00
|
|
|
|
2024-10-14 22:44:01 +02:00
|
|
|
#define SEALEVELPRESSURE_HPA (1013.25)
|
|
|
|
|
#define CORRECTION_FACTOR (8.2296) // for meters
|
2023-07-16 22:47:24 +02:00
|
|
|
|
2024-05-14 05:30:15 +02:00
|
|
|
extern Configuration Config;
|
|
|
|
|
extern String fifthLine;
|
2025-02-24 20:17:01 +01:00
|
|
|
#ifdef HAS_GPS
|
|
|
|
|
extern TinyGPSPlus gps;
|
|
|
|
|
#endif
|
2023-06-18 00:28:40 +02:00
|
|
|
|
2024-05-13 20:00:07 +02:00
|
|
|
int wxModuleType = 0;
|
|
|
|
|
uint8_t wxModuleAddress = 0x00;
|
|
|
|
|
|
2024-05-14 05:30:15 +02:00
|
|
|
float newHum, newTemp, newPress, newGas;
|
|
|
|
|
|
|
|
|
|
|
2024-05-13 20:00:07 +02:00
|
|
|
Adafruit_BME280 bme280;
|
2025-01-10 15:53:52 +01:00
|
|
|
#if defined(HELTEC_V3) || defined(HELTEC_V3_2)
|
2024-05-13 20:00:07 +02:00
|
|
|
Adafruit_BMP280 bmp280(&Wire1);
|
2025-06-19 17:49:37 +02:00
|
|
|
Adafruit_Si7021 si7021 = Adafruit_Si7021();
|
2024-05-13 20:00:07 +02:00
|
|
|
#else
|
|
|
|
|
Adafruit_BMP280 bmp280;
|
2024-05-14 17:43:29 +02:00
|
|
|
Adafruit_BME680 bme680;
|
2025-05-17 17:49:29 +02:00
|
|
|
Adafruit_Si7021 si7021 = Adafruit_Si7021();
|
2025-05-17 17:43:54 +02:00
|
|
|
#endif
|
|
|
|
|
#ifdef LIGHTGATEWAY_PLUS_1_0
|
|
|
|
|
Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();
|
2024-05-13 20:00:07 +02:00
|
|
|
#endif
|
|
|
|
|
|
2024-05-08 21:05:43 +02:00
|
|
|
|
2024-10-05 13:48:08 +02:00
|
|
|
namespace WX_Utils {
|
2023-06-18 00:28:40 +02:00
|
|
|
|
2024-05-13 20:00:07 +02:00
|
|
|
void getWxModuleAddres() {
|
|
|
|
|
uint8_t err, addr;
|
|
|
|
|
for(addr = 1; addr < 0x7F; addr++) {
|
2025-01-10 15:53:52 +01:00
|
|
|
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
|
2024-09-10 19:26:10 +02:00
|
|
|
Wire1.beginTransmission(addr);
|
|
|
|
|
err = Wire1.endTransmission();
|
2024-05-13 20:00:07 +02:00
|
|
|
#else
|
2024-09-10 19:26:10 +02:00
|
|
|
Wire.beginTransmission(addr);
|
2025-05-17 17:43:54 +02:00
|
|
|
#ifdef LIGHTGATEWAY_PLUS_1_0
|
|
|
|
|
Wire.write(0x35);
|
|
|
|
|
Wire.write(0x17);
|
|
|
|
|
#endif
|
2024-09-10 19:26:10 +02:00
|
|
|
err = Wire.endTransmission();
|
2024-05-13 20:00:07 +02:00
|
|
|
#endif
|
|
|
|
|
if (err == 0) {
|
2025-05-17 17:43:54 +02:00
|
|
|
//Serial.println(addr); //this shows any connected board to I2C
|
|
|
|
|
if (addr == 0x76 || addr == 0x77) { // BME or BMP
|
2024-06-10 04:25:15 +02:00
|
|
|
wxModuleAddress = addr;
|
|
|
|
|
return;
|
|
|
|
|
} else if (addr == 0x40) { // Si7011
|
2024-05-13 20:00:07 +02:00
|
|
|
wxModuleAddress = addr;
|
|
|
|
|
return;
|
2025-05-17 17:43:54 +02:00
|
|
|
} else if (addr == 0x70) { // SHTC3
|
|
|
|
|
wxModuleAddress = addr;
|
|
|
|
|
return;
|
2024-05-13 20:00:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-18 00:28:40 +02:00
|
|
|
|
2024-02-24 14:09:05 +01:00
|
|
|
void setup() {
|
2024-10-05 13:48:08 +02:00
|
|
|
if (Config.wxsensor.active) {
|
2025-05-18 14:44:46 +02:00
|
|
|
getWxModuleAddres();
|
2024-05-13 20:00:07 +02:00
|
|
|
if (wxModuleAddress != 0x00) {
|
|
|
|
|
bool wxModuleFound = false;
|
2024-06-10 04:25:15 +02:00
|
|
|
if (wxModuleAddress == 0x76 || wxModuleAddress == 0x77) {
|
2025-01-10 15:53:52 +01:00
|
|
|
#if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY)
|
2024-08-13 23:56:27 +02:00
|
|
|
if (bme280.begin(wxModuleAddress, &Wire1)) {
|
|
|
|
|
Serial.println("BME280 sensor found");
|
2025-05-17 17:43:54 +02:00
|
|
|
wxModuleType = 1;
|
|
|
|
|
wxModuleFound = true;
|
2024-08-13 23:56:27 +02:00
|
|
|
}
|
2024-06-10 04:25:15 +02:00
|
|
|
#else
|
|
|
|
|
if (bme280.begin(wxModuleAddress)) {
|
|
|
|
|
Serial.println("BME280 sensor found");
|
2025-05-17 17:43:54 +02:00
|
|
|
wxModuleType = 1;
|
|
|
|
|
wxModuleFound = true;
|
2024-06-10 04:25:15 +02:00
|
|
|
}
|
|
|
|
|
if (!wxModuleFound) {
|
|
|
|
|
if (bme680.begin(wxModuleAddress)) {
|
|
|
|
|
Serial.println("BME680 sensor found");
|
2025-05-17 17:43:54 +02:00
|
|
|
wxModuleType = 3;
|
|
|
|
|
wxModuleFound = true;
|
2024-06-10 04:25:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2024-05-14 17:43:29 +02:00
|
|
|
if (!wxModuleFound) {
|
2024-06-10 04:25:15 +02:00
|
|
|
if (bmp280.begin(wxModuleAddress)) {
|
|
|
|
|
Serial.println("BMP280 sensor found");
|
2025-05-17 17:43:54 +02:00
|
|
|
wxModuleType = 2;
|
|
|
|
|
wxModuleFound = true;
|
2024-05-14 17:43:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-06-10 04:25:15 +02:00
|
|
|
} else if (wxModuleAddress == 0x40) {
|
2025-05-17 17:49:29 +02:00
|
|
|
if(si7021.begin()) {
|
2024-06-10 04:25:15 +02:00
|
|
|
Serial.println("Si7021 sensor found");
|
2025-05-17 17:43:54 +02:00
|
|
|
wxModuleType = 4;
|
|
|
|
|
wxModuleFound = true;
|
2024-05-14 08:01:24 +02:00
|
|
|
}
|
2025-05-18 06:12:29 +02:00
|
|
|
}
|
|
|
|
|
#ifdef LIGHTGATEWAY_PLUS_1_0
|
|
|
|
|
else if (wxModuleAddress == 0x70) {
|
2025-05-17 17:43:54 +02:00
|
|
|
if (shtc3.begin()) {
|
|
|
|
|
Serial.println("SHTC3 sensor found");
|
|
|
|
|
wxModuleType = 5;
|
|
|
|
|
wxModuleFound = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-05-18 06:12:29 +02:00
|
|
|
#endif
|
2024-05-13 20:00:07 +02:00
|
|
|
if (!wxModuleFound) {
|
2025-05-17 17:43:54 +02:00
|
|
|
displayShow("ERROR", "", "BME/BMP/Si7021/SHTC3 sensor active", "but no sensor found...", 2000);
|
|
|
|
|
Serial.println("BME/BMP/Si7021/SHTC3 sensor Active in config but not found! Check Wiring");
|
2024-05-13 20:00:07 +02:00
|
|
|
} else {
|
|
|
|
|
switch (wxModuleType) {
|
|
|
|
|
case 1:
|
|
|
|
|
bme280.setSampling(Adafruit_BME280::MODE_FORCED,
|
|
|
|
|
Adafruit_BME280::SAMPLING_X1,
|
|
|
|
|
Adafruit_BME280::SAMPLING_X1,
|
|
|
|
|
Adafruit_BME280::SAMPLING_X1,
|
|
|
|
|
Adafruit_BME280::FILTER_OFF
|
|
|
|
|
);
|
|
|
|
|
Serial.println("BME280 Module init done!");
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
bmp280.setSampling(Adafruit_BMP280::MODE_FORCED,
|
|
|
|
|
Adafruit_BMP280::SAMPLING_X1,
|
|
|
|
|
Adafruit_BMP280::SAMPLING_X1,
|
|
|
|
|
Adafruit_BMP280::FILTER_OFF
|
|
|
|
|
);
|
|
|
|
|
Serial.println("BMP280 Module init done!");
|
|
|
|
|
break;
|
2024-05-14 17:43:29 +02:00
|
|
|
case 3:
|
2025-01-10 15:53:52 +01:00
|
|
|
#if !defined(HELTEC_V3) && !defined(HELTEC_V3_2)
|
2024-05-14 17:43:29 +02:00
|
|
|
bme680.setTemperatureOversampling(BME680_OS_1X);
|
|
|
|
|
bme680.setHumidityOversampling(BME680_OS_1X);
|
|
|
|
|
bme680.setPressureOversampling(BME680_OS_1X);
|
|
|
|
|
bme680.setIIRFilterSize(BME680_FILTER_SIZE_0);
|
|
|
|
|
Serial.println("BMP680 Module init done!");
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
2024-05-13 20:00:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-11-06 16:47:42 +01:00
|
|
|
}
|
2024-02-24 14:09:05 +01:00
|
|
|
}
|
2023-06-18 00:28:40 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-05 13:48:08 +02:00
|
|
|
String generateTempString(const float sensorTemp) {
|
|
|
|
|
String strTemp = String((int)sensorTemp);
|
2024-02-24 14:09:05 +01:00
|
|
|
switch (strTemp.length()) {
|
|
|
|
|
case 1:
|
|
|
|
|
return "00" + strTemp;
|
|
|
|
|
case 2:
|
|
|
|
|
return "0" + strTemp;
|
|
|
|
|
case 3:
|
|
|
|
|
return strTemp;
|
|
|
|
|
default:
|
|
|
|
|
return "-999";
|
|
|
|
|
}
|
2023-12-24 15:30:19 +01:00
|
|
|
}
|
2023-06-18 00:28:40 +02:00
|
|
|
|
2024-10-05 13:48:08 +02:00
|
|
|
String generateHumString(const float sensorHum) {
|
|
|
|
|
String strHum = String((int)sensorHum);
|
2024-02-24 14:09:05 +01:00
|
|
|
switch (strHum.length()) {
|
|
|
|
|
case 1:
|
|
|
|
|
return "0" + strHum;
|
|
|
|
|
case 2:
|
|
|
|
|
return strHum;
|
|
|
|
|
case 3:
|
2024-10-05 13:48:08 +02:00
|
|
|
if ((int)sensorHum == 100) {
|
2024-05-14 08:01:24 +02:00
|
|
|
return "00";
|
2024-02-24 14:09:05 +01:00
|
|
|
} else {
|
2024-05-14 08:01:24 +02:00
|
|
|
return "-99";
|
2024-02-24 14:09:05 +01:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
return "-99";
|
2023-12-24 15:30:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-06-18 00:28:40 +02:00
|
|
|
|
2024-10-05 13:48:08 +02:00
|
|
|
String generatePresString(const float sensorPres) {
|
|
|
|
|
String strPress = String((int)sensorPres);
|
|
|
|
|
String decPress = String(int((sensorPres - int(sensorPres)) * 10));
|
2024-02-24 14:09:05 +01:00
|
|
|
switch (strPress.length()) {
|
|
|
|
|
case 1:
|
2024-05-15 18:12:05 +02:00
|
|
|
return "000" + strPress + decPress;
|
2024-02-24 14:09:05 +01:00
|
|
|
case 2:
|
2024-05-15 18:12:05 +02:00
|
|
|
return "00" + strPress + decPress;
|
2024-02-24 14:09:05 +01:00
|
|
|
case 3:
|
2024-05-15 18:12:05 +02:00
|
|
|
return "0" + strPress + decPress;
|
2024-02-24 14:09:05 +01:00
|
|
|
case 4:
|
2024-05-15 18:12:05 +02:00
|
|
|
return strPress + decPress;
|
2024-02-24 14:09:05 +01:00
|
|
|
case 5:
|
|
|
|
|
return strPress;
|
|
|
|
|
default:
|
|
|
|
|
return "-99999";
|
|
|
|
|
}
|
2023-12-24 15:30:19 +01:00
|
|
|
}
|
2023-06-18 00:28:40 +02:00
|
|
|
|
2025-07-30 14:53:02 +02:00
|
|
|
float getAltitudeCorrection() {
|
|
|
|
|
#ifdef HAS_GPS
|
|
|
|
|
return Config.beacon.gpsActive ? gps.altitude.meters() : Config.wxsensor.heightCorrection;
|
|
|
|
|
#else
|
|
|
|
|
return Config.wxsensor.heightCorrection;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-08 20:12:20 +02:00
|
|
|
String readDataSensor() {
|
2024-05-13 20:00:07 +02:00
|
|
|
switch (wxModuleType) {
|
|
|
|
|
case 1: // BME280
|
|
|
|
|
bme280.takeForcedMeasurement();
|
|
|
|
|
newTemp = bme280.readTemperature();
|
|
|
|
|
newPress = (bme280.readPressure() / 100.0F);
|
|
|
|
|
newHum = bme280.readHumidity();
|
|
|
|
|
break;
|
|
|
|
|
case 2: // BMP280
|
|
|
|
|
bmp280.takeForcedMeasurement();
|
|
|
|
|
newTemp = bmp280.readTemperature();
|
|
|
|
|
newPress = (bmp280.readPressure() / 100.0F);
|
|
|
|
|
newHum = 0;
|
|
|
|
|
break;
|
2024-05-14 17:43:29 +02:00
|
|
|
case 3: // BME680
|
2025-01-10 15:53:52 +01:00
|
|
|
#if !defined(HELTEC_V3) && !defined(HELTEC_V3_2)
|
2024-05-14 17:43:29 +02:00
|
|
|
bme680.performReading();
|
|
|
|
|
delay(50);
|
|
|
|
|
if (bme680.endReading()) {
|
|
|
|
|
newTemp = bme680.temperature;
|
|
|
|
|
newPress = (bme680.pressure / 100.0F);
|
|
|
|
|
newHum = bme680.humidity;
|
|
|
|
|
newGas = bme680.gas_resistance / 1000.0; // in Kilo ohms
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
2024-06-10 04:25:15 +02:00
|
|
|
case 4: // Si7021
|
2025-05-17 17:49:29 +02:00
|
|
|
newTemp = si7021.readTemperature();
|
|
|
|
|
newHum = si7021.readHumidity();
|
2025-05-17 17:43:54 +02:00
|
|
|
newPress = 0;
|
2024-06-10 04:25:15 +02:00
|
|
|
break;
|
2025-05-17 17:43:54 +02:00
|
|
|
case 5: // SHTC3
|
2025-05-18 06:12:29 +02:00
|
|
|
#ifdef LIGHTGATEWAY_PLUS_1_0
|
|
|
|
|
sensors_event_t humidity, temp;
|
|
|
|
|
shtc3.getEvent(&humidity, &temp);
|
|
|
|
|
newTemp = temp.temperature;
|
|
|
|
|
newHum = humidity.relative_humidity;
|
|
|
|
|
newPress = 0;
|
|
|
|
|
#endif
|
2025-05-17 17:49:29 +02:00
|
|
|
break;
|
2024-05-13 20:00:07 +02:00
|
|
|
}
|
|
|
|
|
|
2024-02-24 14:09:05 +01:00
|
|
|
if (isnan(newTemp) || isnan(newHum) || isnan(newPress)) {
|
2024-06-10 04:25:15 +02:00
|
|
|
Serial.println("BME/BMP/Si7021 Module data failed");
|
2024-02-24 14:09:05 +01:00
|
|
|
fifthLine = "";
|
2024-10-05 13:48:08 +02:00
|
|
|
return ".../...g...t...";
|
2024-02-24 14:09:05 +01:00
|
|
|
} else {
|
2024-10-05 13:48:08 +02:00
|
|
|
String tempStr = generateTempString(((newTemp + Config.wxsensor.temperatureCorrection) * 1.8) + 32);
|
2024-06-10 04:25:15 +02:00
|
|
|
|
2024-06-21 08:13:34 +02:00
|
|
|
String humStr;
|
2025-05-17 17:43:54 +02:00
|
|
|
if (wxModuleType == 1 || wxModuleType == 3 || wxModuleType == 4 || wxModuleType == 5) {
|
2024-05-11 18:59:07 +02:00
|
|
|
humStr = generateHumString(newHum);
|
2024-05-13 20:00:07 +02:00
|
|
|
} else if (wxModuleType == 2) {
|
2024-05-11 18:59:07 +02:00
|
|
|
humStr = "..";
|
2024-05-13 20:00:07 +02:00
|
|
|
}
|
2024-06-10 04:25:15 +02:00
|
|
|
|
2025-05-17 17:43:54 +02:00
|
|
|
String presStr = (wxModuleType == 4 || wxModuleType == 5)
|
2025-02-24 20:17:01 +01:00
|
|
|
? "....."
|
2025-07-30 14:53:02 +02:00
|
|
|
: generatePresString(newPress + getAltitudeCorrection() / CORRECTION_FACTOR);
|
2025-05-17 17:49:29 +02:00
|
|
|
|
2024-05-30 22:27:07 +02:00
|
|
|
fifthLine = "BME-> ";
|
2024-10-05 13:48:08 +02:00
|
|
|
fifthLine += String(int(newTemp + Config.wxsensor.temperatureCorrection));
|
2024-05-30 22:27:07 +02:00
|
|
|
fifthLine += "C ";
|
|
|
|
|
fifthLine += humStr;
|
|
|
|
|
fifthLine += "% ";
|
|
|
|
|
fifthLine += presStr.substring(0,4);
|
|
|
|
|
fifthLine += "hPa";
|
|
|
|
|
|
2024-10-05 13:48:08 +02:00
|
|
|
String wxPayload = ".../...g...t";
|
|
|
|
|
wxPayload += tempStr;
|
|
|
|
|
wxPayload += "h";
|
|
|
|
|
wxPayload += humStr;
|
|
|
|
|
wxPayload += "b";
|
|
|
|
|
wxPayload += presStr;
|
2024-05-30 22:27:07 +02:00
|
|
|
|
2024-05-13 20:00:07 +02:00
|
|
|
if (wxModuleType == 3) {
|
2024-10-05 13:48:08 +02:00
|
|
|
wxPayload += "Gas: ";
|
|
|
|
|
wxPayload += String(newGas);
|
|
|
|
|
wxPayload += "Kohms";
|
2024-05-13 20:00:07 +02:00
|
|
|
}
|
2024-10-05 13:48:08 +02:00
|
|
|
return wxPayload;
|
2024-02-24 14:09:05 +01:00
|
|
|
}
|
2023-12-24 15:30:19 +01:00
|
|
|
}
|
2023-06-18 00:28:40 +02:00
|
|
|
|
|
|
|
|
}
|