Skip to content

Commit

Permalink
Add support for 8-in-1 Weather Sensor (#131)
Browse files Browse the repository at this point in the history
* Added Weather Station 8-in-1 (s_type == SENSOR_TYPE_WEATHER2)
* Added Globe Thermometer Temperature (ws_tglobe_c)
* Updated library dependencies
  • Loading branch information
matthias-bs authored Feb 9, 2025
1 parent 6eca0b5 commit c9247d1
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 38 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ jobs:
|
#declare -a required_libs=("https://github.com/matthias-bs/BresserWeatherSensorReceiver.git"
declare -a required_libs=(
"BresserWeatherSensorReceiver@0.30.0"
"BresserWeatherSensorReceiver@0.31.0"
"[email protected]"
"LoRa [email protected]"
"[email protected]"
"[email protected]"
"[email protected]"
"[email protected]"
"ATC_MiThermometer@0.4.2"
"ATC_MiThermometer@0.5.0"
"[email protected]"
"[email protected]"
"[email protected]"
Expand Down
2 changes: 2 additions & 0 deletions BresserWeatherSensorLWCfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
// 20240729 Added PowerFeather specific configuration
// 20240730 Modified PF_SUPPLY_MAINTAIN_VOLTAGE
// 20240804 PowerFeather: Added configuration of max. battery charging current
// 20250209 Added Weather Station 8-in-1
//
// Note:
// Depending on board package file date, some defines are written either
Expand Down Expand Up @@ -372,6 +373,7 @@ const uint8_t UBATT_SAMPLES = 10;
#define PAYLOAD_WS_UV 0b00100000
#define PAYLOAD_WS_RAIN_H 0b01000000 // Rain post-processing; hourly rainfall
#define PAYLOAD_WS_RAIN_DWM 0b10000000 // Rain post-processing; daily, weekly, monthly
#define PAYLOAD_WS_TGLOBE 0b0000000100000000

// Lightning sensor
#define PAYLOAD_LIGHTNING_RAW 0b00010000 // Sensor raw data
Expand Down
25 changes: 20 additions & 5 deletions extras/confighelper/confighelper.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
// 20240721 Added tooltips and visual feedback for empty input fields
// 20240725 Added saving of form values to localStorage, added reset to default values
// Added saving/loading of configuration to/from JSON file
// 20250209 Added Globe Thermometer Temperature to Weather Sensor configuration
// (8-in-1 Weather Sensor)
//
// ToDo:
// -
Expand Down Expand Up @@ -100,6 +102,7 @@
weatherWind: true,
weatherUV: true,
weatherLight: false,
weatherTGlobe: false,
weatherRainHourly: true,
weatherRainDWM: true,
multiChannel: true,
Expand Down Expand Up @@ -172,6 +175,8 @@
document.getElementById('weatherUV').style.display = this.checked ? 'inline' : 'none';
document.getElementById('labelWeatherLight').style.display = this.checked ? 'inline' : 'none';
document.getElementById('weatherLight').style.display = this.checked ? 'inline' : 'none';
document.getElementById('labelWeatherTGlobe').style.display = this.checked ? 'inline' : 'none';
document.getElementById('weatherTGlobe').style.display = this.checked ? 'inline' : 'none';
document.getElementById('labelWeatherRainHourly').style.display = this.checked ? 'inline' : 'none';
document.getElementById('weatherRainHourly').style.display = this.checked ? 'inline' : 'none';
document.getElementById('labelWeatherRainDWM').style.display = this.checked ? 'inline' : 'none';
Expand Down Expand Up @@ -521,6 +526,7 @@
}
let size = 0;
let result = 1;
let result2 = 0;
const weatherConfig = [
['weatherTemperature', 2, 'ws_temp_c', 'temperature'],
['weatherHumidity', 1, 'ws_humidity', 'uint8'],
Expand All @@ -529,15 +535,15 @@
['weatherLight', 4, 'ws_light_lux', 'uint32'],
['weatherUV', 1, 'ws_uv', 'uint8fp1'],
['weatherRainHourly', 4, 'ws_rain_hourly_mm', 'rawfloat'],
['weatherRainDWM', 12, ['ws_rain_daily_mm', 'ws_rain_weekly_mm', 'ws_rain_monthly_mm'], ['rawfloat', 'rawfloat', 'rawfloat']]
['weatherRainDWM', 12, ['ws_rain_daily_mm', 'ws_rain_weekly_mm', 'ws_rain_monthly_mm'], ['rawfloat', 'rawfloat', 'rawfloat']],
['weatherTGlobe', 2, 'ws_tglobe_c', 'temperature']
];
size += weatherConfig[0][1];
configDecoder.signals.push("'" + weatherConfig[0][2] + "'");
configDecoder.types.push(weatherConfig[0][3]);
for (var i = 1; i < weatherConfig.length; i++) {
var checkbox = document.getElementById(weatherConfig[i][0]);
if (checkbox.checked) {
result |= (1 << i);
size += weatherConfig[i][1];
signals = weatherConfig[i][2];
var _signals = [];
Expand All @@ -546,11 +552,17 @@
} else {
_signals = "'" + signals + "'";
}
if (i == 8) {
// Globe Thermometer Temperature
result2 |= 1;
} else {
result |= (1 << i);
}
configDecoder.signals.push(_signals);
configDecoder.types.push(weatherConfig[i][3]);
}
}
return [size, result];
return [size, result, result2];
}

// Get [size, bitmap] from the Lightning Sensor configuration selected with checkboxes
Expand Down Expand Up @@ -635,7 +647,7 @@
};

// Add Bresser weather sensor
[size, weatherValue] = getWeatherconfig(configDecoder);
[size, weatherValue, weatherValue2] = getWeatherconfig(configDecoder);
totalSize += size;

// Add multi-channel Bresser sensors
Expand Down Expand Up @@ -710,6 +722,7 @@
document.getElementById('size').value = totalSize;

configArray[1] = weatherValue;
configArray[13] = weatherValue2;

// Get the current JSON output
let jsonOutput = JSON.parse(document.getElementById('jsonOutput').value);
Expand Down Expand Up @@ -806,6 +819,8 @@ <h2>Input</h2>
<input type="checkbox" id="weatherUV" name="weatherUV">
<label for="weatherLight" id="labelWeatherLight">Light:</label>
<input type="checkbox" id="weatherLight" name="weatherLight">
<label for="weatherTGlobe" id="labelWeatherTGlobe">Globe Thermometer:</label>
<input type="checkbox" id="weatherTGlobe" name="weatherTGlobe">
<label for="weatherRainHourly" id="labelWeatherRainHourly">Hourly Rain:</label>
<input type="checkbox" id="weatherRainHourly" name="weatherRainHourly">
<label for="weatherRainDWM" id="labelWeatherRainDWM">Daily/Weekly/Monthly Rain:</label>
Expand Down Expand Up @@ -884,7 +899,7 @@ <h2>Output</h2>
<br>
<br>
<p style="font-size: smaller;">
Copyright &copy; 2024 Matthias Prinke, MIT License
Copyright &copy; 2025 Matthias Prinke, MIT License
</p>
</body>

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
},
"homepage": "https://github.com/matthias-bs/BresserWeatherSensorLW#README",
"dependencies": {
"BresserWeatherSensorReceiver": "matthias-bs/BresserWeatherSensorReceiver#semver:^0.30.0",
"BresserWeatherSensorReceiver": "matthias-bs/BresserWeatherSensorReceiver#semver:^0.31.0",
"RadioLib": "jgromes/RadioLib#semver:^7.1.2",
"lora-serialization": "thesolarnomad/lora-serialization#semver:^3.3.1",
"ESP32Time": "fbiego/ESP32Time#semver:^2.0.6",
"OneWireNg": "https://github.com/pstolarz/OneWireNg#semver:^0.14.0",
"Arduino-Temperature-Control-Library": "milesburton/Arduino-Temperature-Control-Library#semver:^4.0.2",
"NimBLE-Arduino": "h2zero/NimBLE-Arduino#semver:^2.2.1",
"ATC_MiThermometer": "matthias-bs/ATC_MiThermometer#semver:^0.4.2",
"ATC_MiThermometer": "matthias-bs/ATC_MiThermometer#semver:^0.5.0",
"TheengsDecoder": "theengs/decoder#semver:^1.8.4",
"Preferences": "vshymanskyy/Preferences#semver:^2.1.0",
"ArduinoJson": "bblanchon/ArduinoJson#semver:^7.3.0"
Expand Down
24 changes: 17 additions & 7 deletions scripts/uplink_formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@
// 20240722 Added CMD_SET_LW_STATUS_INTERVAL, modified CMD_GET_LW_CONFIG,
// renamed CMD_SET_STATUS_INTERVAL to CMD_SET_APP_STATUS_INTERVAL
// 20240729 Added PowerFeather specific status information
// 20250209 Changed flags in found_sensors() from 8 to 16 bits
// Added ws_tglobe_c
//
// ToDo:
// -
Expand Down Expand Up @@ -199,7 +201,7 @@ function decoder(bytes, port) {
10: "CO2 Sensor",
11: "Air Quality Sensor (HCHO and VOC)",
12: "undefined",
13: "undefined",
13: "Weather Sensor (8-in-1)",
14: "undefined",
15: "undefined"
};
Expand Down Expand Up @@ -539,8 +541,8 @@ function decoder(bytes, port) {
const decoded_type = sensor_types[tmp & 0x0F];
const decoded_decoder = sensor_decoders[tmp >> 4];
const decoded_channel = uint8(bytes.slice(i + 5, i + 6));
const decoded_flags = "0x" + byte2hex(bytes[i + 6]);
const decoded_rssi = -uint8(bytes.slice(i + 7, i + 8));
const decoded_flags = "0x" + byte2hex(bytes[i + 7]) + byte2hex(bytes[i + 6]);
const decoded_rssi = -uint8(bytes.slice(i + 8, i + 9));
res.push({
'id': decoded_id,
'type': decoded_type,
Expand Down Expand Up @@ -664,9 +666,11 @@ function decoder(bytes, port) {
uint8,
rawfloat,
uint16fp1, uint16fp1, uint16fp1,
uint8fp1,
//uint32,
//uint8fp1,
rawfloat,
rawfloat, rawfloat, rawfloat,
//temperature,
temperature, uint8,
temperature, uint8,
unixtime,
Expand All @@ -682,9 +686,11 @@ function decoder(bytes, port) {
'ws_humidity',
'ws_rain_mm',
'ws_wind_gust_ms', 'ws_wind_avg_ms', 'ws_wind_dir_deg',
'ws_uv',
//'ws_light_lux',
//'ws_uv',
'ws_rain_hourly_mm',
'ws_rain_daily_mm', 'ws_rain_weekly_mm', 'ws_rain_monthly_mm',
//'ws_tglobe_c',
'th1_temp_c', 'th1_humidity',
'soil1_temp_c', 'soil1_moisture',
'lgt_ev_time',
Expand All @@ -706,9 +712,11 @@ function decoder(bytes, port) {
uint8,
rawfloat,
uint16fp1, uint16fp1, uint16fp1,
uint8fp1,
//uint32,
//uint8fp1,
rawfloat,
rawfloat, rawfloat, rawfloat,
//temperature,
temperature, uint8,
temperature, uint8,
unixtime,
Expand All @@ -725,9 +733,11 @@ function decoder(bytes, port) {
'humidity',
'rain_mm',
'wind_gust_meter_sec', 'wind_avg_meter_sec', 'wind_direction_deg',
'ws_uv', // new
//'ws_light_lux',
//'ws_uv', // new
'rain_hr',
'rain_day', 'rain_week', 'rain_month',
//'ws_tglobe_c',
'th1_temp_c', 'th1_humidity', //new
'soil_temp_c', 'soil_moisture',
'lightning_time',
Expand Down
79 changes: 61 additions & 18 deletions src/PayloadBresser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
// 20240718 Fixed premature return from begin() leading to empty payload
// 20240719 Fixed enabling of all decoders in scanBresser()
// 20240821 Fixed validation of rain statistics
// 20250209 Added Weather Station 8-in-1
//
// ToDo:
// - Add handling of Professional Rain Gauge
Expand Down Expand Up @@ -119,9 +120,10 @@ void PayloadBresser::scanBresser(uint8_t ws_scantime, LoraEncoder &encoder)
break;
}
}
uint8_t flags = 0;
uint16_t flags = 0;
if ((weatherSensor.sensor[i].s_type == SENSOR_TYPE_WEATHER0) ||
(weatherSensor.sensor[i].s_type == SENSOR_TYPE_WEATHER1))
(weatherSensor.sensor[i].s_type == SENSOR_TYPE_WEATHER1) ||
(weatherSensor.sensor[i].s_type == SENSOR_TYPE_WEATHER2))
{
if (weatherSensor.sensor[i].w.temp_ok)
flags |= 0x1;
Expand All @@ -135,6 +137,8 @@ void PayloadBresser::scanBresser(uint8_t ws_scantime, LoraEncoder &encoder)
flags |= 0x10;
if (weatherSensor.sensor[i].w.light_ok)
flags |= 0x20;
if (weatherSensor.sensor[i].w.tglobe_ok)
flags |= 0x100;
}

encoder.writeUint8(weatherSensor.sensor[i].sensor_id >> 24);
Expand All @@ -143,7 +147,7 @@ void PayloadBresser::scanBresser(uint8_t ws_scantime, LoraEncoder &encoder)
encoder.writeUint8(weatherSensor.sensor[i].sensor_id & 0xFF);
encoder.writeUint8((decoder << 4) | weatherSensor.sensor[i].s_type);
encoder.writeUint8(weatherSensor.sensor[i].chan);
encoder.writeUint8(flags);
encoder.writeUint16(flags);
encoder.writeUint8(static_cast<uint8_t>(-weatherSensor.sensor[i].rssi));
}

Expand All @@ -158,9 +162,11 @@ void PayloadBresser::encodeBresser(uint8_t *appPayloadCfg, uint8_t *appStatus, L
if (weatherSensor.sensor.size() == 0)
return;

// Handle weather sensors - which only have one channel (0) - first.
// Handle weather sensors - which only have one channel (ch 0) - first.
// Configuration for SENSOR_TYPE_WEATHER0 is integrated into SENSOR_TYPE_WEATHER1.
uint8_t flags = appPayloadCfg[1];
// Configuration for SENSOR_TYPE_WEATHER2 uses flags in appPayloadCFG[1] and
// appPayloadCfg[13].
uint16_t flags = (appPayloadCfg[13] << 8) | appPayloadCfg[1];
if (flags & 1)
{
// Try to find SENSOR_TYPE_WEATHER1
Expand All @@ -171,9 +177,18 @@ void PayloadBresser::encodeBresser(uint8_t *appPayloadCfg, uint8_t *appStatus, L
}
else
{
// Try to find SENSOR_TYPE_WEATHER0
idx = weatherSensor.findType(SENSOR_TYPE_WEATHER0);
rainGauge.set_max(1000);
// Try to find SENSOR_TYPE_WEATHER2
idx = weatherSensor.findType(SENSOR_TYPE_WEATHER2);
if (idx > -1)
{
rainGauge.set_max(100000);
}
else
{
// Try to find SENSOR_TYPE_WEATHER0
idx = weatherSensor.findType(SENSOR_TYPE_WEATHER0);
rainGauge.set_max(1000);
}
}

#ifdef RAINDATA_EN
Expand Down Expand Up @@ -205,6 +220,10 @@ void PayloadBresser::encodeBresser(uint8_t *appPayloadCfg, uint8_t *appStatus, L
if (appPayloadCfg[type] == 0)
continue;

// Skip Weather Sensor 8-in-1 (handled above)
if (type == SENSOR_TYPE_WEATHER2)
continue;

#ifdef LIGHTNINGSENSOR_EN
// Lightning sensor has fixed channel (0)
if (type == SENSOR_TYPE_LIGHTNING)
Expand Down Expand Up @@ -290,18 +309,19 @@ void PayloadBresser::encodeBresser(uint8_t *appPayloadCfg, uint8_t *appStatus, L
}
}

// Payload size: 2...17 bytes (ENCODE_AS_FLOAT == false) / 2...23 bytes (ENCODE_AS_FLOAT == true)
void PayloadBresser::encodeWeatherSensor(int idx, uint8_t flags, LoraEncoder &encoder)
// Payload size: 2...19 bytes (ENCODE_AS_FLOAT == false) / 2...25 bytes (ENCODE_AS_FLOAT == true)
void PayloadBresser::encodeWeatherSensor(int idx, uint16_t flags, LoraEncoder &encoder)
{
// Weather Stations Professional 3-in-1 Professional
// 5-in-1 6-in-1 7-in-1 Rain Gauge Wind Gauge
// Weather Stations Professional 3-in-1 Professional
// 5-in-1 6-in-1 7-in-1 8-in-1 Rain Gauge Wind Gauge
//
// Temperature X X X X X
// Humidity X X X X
// Wind X X X X
// Rain X X X X
// UV X X
// Light Intensity X
// Temperature X X X X X X
// Humidity X X X X X
// Wind X X X X X
// Rain X X X X X
// UV X X X
// Light Intensity X X
// Globe Thermometer X

if (idx == -1)
{
Expand Down Expand Up @@ -471,6 +491,29 @@ void PayloadBresser::encodeWeatherSensor(int idx, uint8_t flags, LoraEncoder &en
}
}
#endif

// Additional sensor (8-in-1)
if (idx == -1)
{
if (flags & PAYLOAD_WS_TGLOBE)
encoder.writeTemperature(INV_TEMP); // Globe Thermometer
}
else
{
if (flags & PAYLOAD_WS_TGLOBE)
{
if (weatherSensor.sensor[idx].w.tglobe_ok)
{
log_i("Globe Thermometer: %3.1f °C", weatherSensor.sensor[idx].w.tglobe_c);
encoder.writeTemperature(weatherSensor.sensor[idx].w.tglobe_c);
}
else
{
log_i("Globe Thermometer: --.- °C");
encoder.writeTemperature(INV_TEMP);
}
}
}
}

void PayloadBresser::encodeThermoHygroSensor(int idx, LoraEncoder &encoder)
Expand Down
Loading

0 comments on commit c9247d1

Please sign in to comment.