Retrieves weather information from a WeatherLink Live and publishes it to an MQTT broker.
weatherlink-mqtt, you can run
cargo install weatherlink-mqtt.
weatherlink-mqtt exposes options via a mix of envvars and a TOML config file.
These are the supported envvars:
LOG_LEVEL: Amount of logging you'd like to have. Defaults to
info, set to
tracefor more logs or
offfor fewer logs.
I'm personally using
weatherlink-mqtt to collect data for a Davis Vantage Vue, where the collected data (a mix of HTTP polling and UDP broadcast) is collated and streamed to an offsite MQTT broker (Mosquitto). The MQTT topics are then consumed and processed by a WeeWX instance via the
WeeWX-MQTTSubscribe plugin. But the data sent to MQTT is a nearly as-is copy of WeatherLink output which should be usable by any consumer.
weatherlink-mqtt in a docker container. The container is run with
--network=host networking so that it can receive local UDP broadcast packets from the WeatherLink Live. I'm using these arguments pointing it to the MQTT broker:
/weatherlink-mqtt \ --mqtt-url mqtt://<broker-ip>:1883?client_id=weatherlink-mqtt \ --mqtt-topic-prefix weather.json/
On the consumer side, there's mapping the WeatherLink data to the names/units that WeeWX expects. The following is how I've configured
WeeWX-MQTTSubscribe in my
weewx.conf to do this. This includes mapping input field names to their equivalents in WeeWX, while also e.g. converting 0.01" bucket tip counts to incremental inches of rain. Depending on your hardware, you may need to change things, or this might mostly work as-is:
[MQTTSubscribeDriver] driver = user.MQTTSubscribe host = <broker-ip> port = 1883 keepalive = 60 log = true [[message_callback]] type = json # use / in field names to delimit json levels flatten_delimiter = "/" [[topics]] unit_system = US [[[weather.json/txid1]]] ignore = true [[[[temp]]]] # most recent valid temperature (°F) ignore = false name = outTemp [[[[hum]]]] # most recent valid humidity (%RH) ignore = false name = outHumidity [[[[dew_point]]]] # (°F) ignore = false name = dewpoint [[[[wet_bulb]]]] # (°F) ignore = false name = wetbulb [[[[heat_index]]]] # (°F) ignore = false name = heatindex [[[[wind_chill]]]] # (°F) ignore = false name = windchill [[[[thw_index]]]] # (°F) ignore = false name = thw [[[[wind_speed_last]]]] # most recent valid wind speed (mph) ignore = false name = windSpeed [[[[wind_dir_last]]]] # most recent valid wind direction (°degree) ignore = false name = windDir # We want to record the DIFF in bucket tips over time to weewx. # Sending the value as-is gets summed across EACH 2s report, leading to hugely exaggerated rain! # Let's go with the longest timespan - the annual value. This avoids not detecting value rollover. # The diff logic is smart enough to avoid reporting a big initial value as a big diff. # As such we ignore rain_rate_last and rain_60_min in favor of rain_24_hr, to increase the likelihood # of detecting a decrease when the value rolls over. The rate/1h values risk the rate staying exactly # the same across intervals, in which case we won't detect the diff. # Meanwhile we don't worry about the longer amounts like rainfall_monthly and rainfall_yearly because # if weewx is restarted then those will appear to have large diffs that will get recorded all at once. [[[[rainfall_year]]]] # total rain count since start of year (counts) ignore = false name = rain # enables recording diffs, see also: # https://github.com/bellrichm/WeeWX-MQTTSubscribe/blob/master/bin/user/MQTTSubscribe.py#L1273-L1277 contains_total = true # if the value goes from 1234 back to 1, then report the 1 as a diff wrap_around = true # each count is 0.01" conversion_func = lambda x: x / 100. [[[[rain_60_min]]]] # total rain count over last 60 min (counts) ignore = false name = hourRain # each count is 0.01" conversion_func = lambda x: x / 100. [[[[rain_24_hr]]]] # total rain count over last 24 hours (counts) ignore = false name = rain24 # each count is 0.01" conversion_func = lambda x: x / 100. [[[[rainfall_daily]]]] # total rain count since local midnight (counts) ignore = false name = dayRain # each count is 0.01" conversion_func = lambda x: x / 100. [[[[solar_rad]]]] # most recent solar radiation (W/m²) ignore = true # null in my data name = radiation # watt_per_meter_squared [[[[uv_index]]]] # most recent UV index (Index) ignore = true # null in my data name = UV [[[[trans_battery_flag]]]] # transmitter battery status flag (no unit) ignore = false name = outTempBatteryStatus [[[weather.json/local]]] ignore = true [[[[temp_in]]]] # most recent valid inside temp (°F) ignore = false name = inTemp [[[[hum_in]]]] # most recent valid inside humidity (%RH) ignore = false name = inHumidity [[[[dew_point_in]]]] # (°F) ignore = false name = inDewpoint [[[[heat_index_in]]]] # (°F) ignore = false name = inHeatindex # maybe? [[[[bar_sea_level]]]] # most recent bar sensor reading with elevation adjustment (inches) ignore = false name = barometer [[[[bar_absolute]]]] # raw bar sensor reading (inches) ignore = false name = pressure
This project is licensed under the AGPLv3 (or later) and is copyright Nicholas Parker.