/* 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 . */ #include #ifdef LIGHTGATEWAY_PLUS_1_0 #include "Adafruit_SHTC3.h" #endif #include "configuration.h" #include "board_pinout.h" #include "wx_utils.h" #include "display.h" #define SEALEVELPRESSURE_HPA (1013.25) #define CORRECTION_FACTOR (8.2296) // for meters extern Configuration Config; extern String fifthLine; #ifdef HAS_GPS extern TinyGPSPlus gps; #endif int wxModuleType = 0; uint8_t wxModuleAddress = 0x00; float newHum, newTemp, newPress, newGas; Adafruit_BME280 bme280; Adafruit_AHTX0 aht20; #if defined(HELTEC_V3) || defined(HELTEC_V3_2) Adafruit_BMP280 bmp280(&Wire1); Adafruit_Si7021 si7021 = Adafruit_Si7021(); #else Adafruit_BMP280 bmp280; Adafruit_BME680 bme680; Adafruit_Si7021 si7021 = Adafruit_Si7021(); #endif #ifdef LIGHTGATEWAY_PLUS_1_0 Adafruit_SHTC3 shtc3 = Adafruit_SHTC3(); #endif namespace WX_Utils { void getWxModuleAddres() { uint8_t err, addr; for(addr = 1; addr < 0x7F; addr++) { #if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY) Wire1.beginTransmission(addr); err = Wire1.endTransmission(); #else Wire.beginTransmission(addr); #ifdef LIGHTGATEWAY_PLUS_1_0 Wire.write(0x35); Wire.write(0x17); #endif err = Wire.endTransmission(); #endif delay(5); if (err == 0) { //Serial.println(addr); //this shows any connected board to I2C if (addr == 0x76 || addr == 0x77) { // BME or BMP wxModuleAddress = addr; return; } else if (addr == 0x40) { // Si7011 wxModuleAddress = addr; return; } else if (addr == 0x70) { // SHTC3 wxModuleAddress = addr; return; } } } } void setup() { if (Config.wxsensor.active) { getWxModuleAddres(); if (wxModuleAddress != 0x00) { bool wxModuleFound = false; if (wxModuleAddress == 0x76 || wxModuleAddress == 0x77) { #if defined(HELTEC_V3) || defined(HELTEC_V3_2) || defined(HELTEC_WSL_V3) || defined(HELTEC_WSL_V3_DISPLAY) if (bme280.begin(wxModuleAddress, &Wire1)) { Serial.println("BME280 sensor found"); wxModuleType = 1; wxModuleFound = true; } #else if (bme280.begin(wxModuleAddress)) { Serial.println("BME280 sensor found"); wxModuleType = 1; wxModuleFound = true; } if (!wxModuleFound) { if (bme680.begin(wxModuleAddress)) { Serial.println("BME680 sensor found"); wxModuleType = 3; wxModuleFound = true; } } #endif if (!wxModuleFound) { if (bmp280.begin(wxModuleAddress)) { Serial.println("BMP280 sensor found"); wxModuleType = 2; wxModuleFound = true; if (aht20.begin()) { Serial.println("AHT20 sensor found"); if (wxModuleType == 2) wxModuleType = 6; } } } } else if (wxModuleAddress == 0x40) { if(si7021.begin()) { Serial.println("Si7021 sensor found"); wxModuleType = 4; wxModuleFound = true; } } #ifdef LIGHTGATEWAY_PLUS_1_0 else if (wxModuleAddress == 0x70) { if (shtc3.begin()) { Serial.println("SHTC3 sensor found"); wxModuleType = 5; wxModuleFound = true; } } #endif if (!wxModuleFound) { 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"); } 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; case 3: #if !defined(HELTEC_V3) && !defined(HELTEC_V3_2) 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; } } } } } String generateTempString(const float sensorTemp) { String strTemp = String((int)sensorTemp); switch (strTemp.length()) { case 1: return "00" + strTemp; case 2: return "0" + strTemp; case 3: return strTemp; default: return "-999"; } } String generateHumString(const float sensorHum) { String strHum = String((int)sensorHum); switch (strHum.length()) { case 1: return "0" + strHum; case 2: return strHum; case 3: if ((int)sensorHum == 100) { return "00"; } else { return "-99"; } default: return "-99"; } } String generatePresString(const float sensorPres) { String strPress = String((int)sensorPres); String decPress = String(int((sensorPres - int(sensorPres)) * 10)); switch (strPress.length()) { case 1: return "000" + strPress + decPress; case 2: return "00" + strPress + decPress; case 3: return "0" + strPress + decPress; case 4: return strPress + decPress; case 5: return strPress; default: return "-99999"; } } float getAltitudeCorrection() { #ifdef HAS_GPS return Config.beacon.gpsActive ? gps.altitude.meters() : Config.wxsensor.heightCorrection; #else return Config.wxsensor.heightCorrection; #endif } String readDataSensor() { 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; case 3: // BME680 #if !defined(HELTEC_V3) && !defined(HELTEC_V3_2) 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; case 4: // Si7021 newTemp = si7021.readTemperature(); newHum = si7021.readHumidity(); newPress = 0; break; case 5: // SHTC3 #ifdef LIGHTGATEWAY_PLUS_1_0 sensors_event_t humidity, temp; shtc3.getEvent(&humidity, &temp); newTemp = temp.temperature; newHum = humidity.relative_humidity; newPress = 0; #endif break; case 6: // BMP280 + AHT20 bmp280.takeForcedMeasurement(); newTemp = bmp280.readTemperature(); newPress = (bmp280.readPressure() / 100.0F); sensors_event_t humidity, temp; aht20.getEvent(&humidity, &temp); newHum = humidity.relative_humidity; break; } if (isnan(newTemp) || isnan(newHum) || isnan(newPress)) { Serial.println("BME/BMP/Si7021 Module data failed"); fifthLine = ""; return ".../...g...t..."; } else { String tempStr = generateTempString(((newTemp + Config.wxsensor.temperatureCorrection) * 1.8) + 32); String humStr; if (wxModuleType == 1 || wxModuleType == 3 || wxModuleType == 4 || wxModuleType == 5 || wxModuleType == 6) { humStr = generateHumString(newHum); } else if (wxModuleType == 2) { humStr = ".."; } String presStr = (wxModuleType == 4 || wxModuleType == 5) ? "....." : generatePresString(newPress + getAltitudeCorrection() / CORRECTION_FACTOR); fifthLine = "BME-> "; fifthLine += String(int(newTemp + Config.wxsensor.temperatureCorrection)); fifthLine += "C "; fifthLine += humStr; fifthLine += "% "; fifthLine += presStr.substring(0,4); fifthLine += "hPa"; String wxPayload = ".../...g...t"; wxPayload += tempStr; wxPayload += "h"; wxPayload += humStr; wxPayload += "b"; wxPayload += presStr; if (wxModuleType == 3) { wxPayload += "Gas: "; wxPayload += String(newGas); wxPayload += "Kohms"; } return wxPayload; } } }