pywws.service.mqtt

Upload weather data to MQTT message broker.

MQTT is a “message broker” system, typically running on localhost or another computer in your home network. Use of MQTT with pywws requires an additional library. See Dependencies - MQTT for details.

  • Mosquitto (a lightweight broker): http://mosquitto.org/

  • Example weather.ini configuration:

    [mqtt]
    topic = /weather/pywws
    hostname = localhost
    port = 1883
    client_id = pywws
    retain = False
    user =
    password =
    tls_cert = /home/pi/pywws/ca_cert/mqtt_ca.crt
    tls_ver = 2
    multi_topic = False
    
    [logged]
    services = ['mqtt', 'underground']
    
  • To customize the MQTT message use template_txt (remove illuminace and uv if weather station does not support them):

    [mqtt]
    ... (as above)
    template_txt = ('\n'
            '#idx          \'"idx"         : "%Y-%m-%d %H:%M:%S",\'#\n'
            '#wind_dir     \'"wind_dir_degrees"    : "%.d",\' \'\' \'winddir_degrees(x)\'#\n'
            '#wind_dir     \'"wind_dir_text"       : "%s",\' \'\' \'winddir_text(x)\'#\n'
            '#wind_ave     \'"wind_ave_mps"    : "%.2f",\'#\n'
            '#wind_ave     \'"wind_ave_mph"    : "%.2f",\' \'\' \'wind_mph(x)\'#\n'
            '#wind_gust    \'"wind_gust_mps"   : "%.2f",\'#\n'
            '#wind_gust    \'"wind_gust_mph"   : "%.2f",\' \'\' \'wind_mph(x)\'#\n'
            '#calc \'wind_chill(data["temp_out"],data["wind_ave"])\' \'"wind_chill_c" : "%.1f",\'#\n'
            '#calc \'temp_f(wind_chill(data["temp_out"],data["wind_ave"]))\' \'"wind_chill_f" : "%.1f",\'#\n'
            '#calc \'dew_point(data["temp_out"],data["hum_out"])\' \'"dew_point_c" : "%.1f",\'#\n'
            '#calc \'temp_f(dew_point(data["temp_out"],data["hum_out"]))\' \'"dew_point_f" : "%.1f",\'#\n'
            '#hum_out      \'"hum_out"     : "%.d",\'#\n'
            '#hum_in       \'"hum_in"      : "%.d",\'#\n'
            '#temp_in      \'"temp_in_c"   : "%.1f",\'#\n'
            '#temp_in      \'"temp_in_f"   : "%.1f",\' \'\' \'temp_f(x)\'#\n'
            '#temp_out     \'"temp_out_c"  : "%.1f",\'#\n'
            '#temp_out     \'"temp_out_f"  : "%.1f",\' \'\' \'temp_f(x)\'#\n'
            '#calc \'apparent_temp(data["temp_out"],data["hum_out"],data["wind_ave"])\' \'"temp_out_realfeel_c" : "%.1f",\'#\n'
            '#calc \'temp_f(apparent_temp(data["temp_out"],data["hum_out"],data["wind_ave"]))\' \'"temp_out_realfeel_f" : "%.1f",\'#\n'
            '#rel_pressure \'"pressure_rel_hpa": "%.1f",\'#\n'
            '#rel_pressure \'"pressure_rel_inhg": "%.4f",\' \'\' \'pressure_inhg(x)\'#\n'
            '#abs_pressure \'"pressure_abs_hpa": "%.1f",\'#\n'
            '#abs_pressure \'"pressure_abs_inhg": "%.4f",\' \'\' \'pressure_inhg(x)\'#\n'
            '#rain         \'"rain_mm"     : "%.1f",\'#\n'
            '#rain         \'"rain_in"     : "%.2f",\' \'\' \'rain_inch(x)\'#\n'
            '#calc \'rain_hour(data)\' \'"rain_last_hour_mm": "%.1f",\'#\n'
            '#calc \'rain_inch(rain_hour(data))\' \'"rain_last_hour_in": "%.2f",\'#\n'
            '#calc \'rain_24hr(data)\' \'"rain_last_24hours_mm": "%.1f",\'#\n'
            '#calc \'rain_inch(rain_24hr(data))\' \'"rain_last_24hours_in": "%.2f",\'#\n'
            '#calc \'rain_day(data)\' \'"rain_day_mm": "%.1f",\'#\n'
            '#calc \'rain_inch(rain_day(data))\' \'"rain_day_in": "%.2f",\'#\n'
            '#illuminance  \'"illuminance_lux" : "%.1f",\'#\n'
            '#illuminance  \'"illuminance_wm2" : "%.2f",\' \'\' \'illuminance_wm2(x)\'#\n'
            '#uv           \'"uv"          : "%.d",\'#\n'
            '\n')
    

pywws will publish a JSON string of weather data. This data will be published to the broker running on hostname, with the port number specified. (An IP address can be used instead of a host name.) client_id is a note of who published the data to the topic. topic can be any string value, this needs to be the topic that a subscriber is aware of.

retain is a boolean and should be set to True or False. If set to True this will flag the message sent to the broker to be retained. Otherwise the broker discards the message if no client is subscribing to this topic. This allows clients to get an immediate response when they subscribe to a topic, without having to wait until the next message is published.

user and password can be used for MQTT authentication.

tls_cert and tls_ver are used for MQTT TLS security. Set tls_cert as the path to a CA certificate (e.g. tls_cert = /home/pi/pywws/ca_cert/mqtt_ca.crt) and tls_ver to the TLS version (e.g. tls_ver = 2) (TLS1.2 recommended). See https://mosquitto.org/man/mosquitto-tls-7.html for information on how to generate certificates. Only copy the ca.crt to your pywws client. See http://www.steves-internet-guide.com/mosquitto-tls/ for a step-by-step guide to securing your MQTT server. Note that secure MQTTS usually uses port 8883, so you will need to also change the port number.

multi_topic is a boolean and should be set to True or False. If set to True pywws will also publish all the data each as separate subtopics of the configured topic; e.g., with the topic set to /weather/pywws pywws will also publish the outside temperature to /weather/pywws/temp_out_c and the inside temperature to /weather/pywws/temp_in_c.

template_txt is the template used to generate the data to be published. You can edit it to suit your own requirements. Be very careful about the backslash escaped quotation marks though. If not specified default will be used, which sends a lot of values in metric and imperial units.

Changed in version NN.N: Default for template_txt was updated. This change is not backwards compatible, the original values are still present, just under new names. New default tries to send most of the values pywws collects in both metric and imperial units. This is to make it easier for new users to get going.

If these aren’t obvious to you it’s worth doing a bit of reading around MQTT. It’s a great lightweight messaging system from IBM, recently made more popular when Facebook published information on their use of it.

This has been tested with the Mosquitto Open Source MQTT broker, running on a Raspberry Pi (Raspian OS). TLS (mqtt data encryption) is not yet implemented.

Thanks to Matt Thompson for writing the MQTT code and to Robin Kearney for adding the retain and auth options.

Classes

ToService(context[, check_params])
class pywws.service.mqtt.ToService(context, check_params=True)[source]

Bases: pywws.service.LiveDataService

config = {'client_id': ('pywws', True, None), 'hostname': ('localhost', True, None), 'multi_topic': ('False', True, None), 'password': ('', False, None), 'port': ('1883', True, None), 'retain': ('False', True, None), 'tls_cert': ('', False, None), 'tls_ver': ('1', True, None), 'topic': ('/weather/pywws', True, None), 'user': ('', False, None)}
logger = <Logger pywws.service.mqtt (WARNING)>
service_name = 'mqtt'
template_3080_add = '\n#illuminance \'"illuminance_lux" : "%.1f",\'#\n#illuminance \'"illuminance_wm2" : "%.2f",\' \'\' \'illuminance_wm2(x)\'#\n#uv \'"uv" : "%.d",\'#\n'
template = '\n#idx \'"idx" : "%Y-%m-%d %H:%M:%S",\'#\n#wind_dir \'"wind_dir_degrees": "%.d",\' \'\' \'winddir_degrees(x)\'#\n#wind_dir \'"wind_dir_text" : "%s",\' \'\' \'winddir_text(x)\'#\n#wind_ave \'"wind_ave_mps" : "%.2f",\'#\n#wind_ave \'"wind_ave_mph" : "%.2f",\' \'\' \'wind_mph(x)\'#\n#wind_gust \'"wind_gust_mps" : "%.2f",\'#\n#wind_gust \'"wind_gust_mph" : "%.2f",\' \'\' \'wind_mph(x)\'#\n#calc \'wind_chill(data["temp_out"],data["wind_ave"])\' \'"wind_chill_c" : "%.1f",\'#\n#calc \'temp_f(wind_chill(data["temp_out"],data["wind_ave"]))\' \'"wind_chill_f" : "%.1f",\'#\n#calc \'dew_point(data["temp_out"],data["hum_out"])\' \'"dew_point_c" : "%.1f",\'#\n#calc \'temp_f(dew_point(data["temp_out"],data["hum_out"]))\' \'"dew_point_f" : "%.1f",\'#\n#hum_out \'"hum_out" : "%.d",\'#\n#hum_in \'"hum_in" : "%.d",\'#\n#temp_in \'"temp_in_c" : "%.1f",\'#\n#temp_in \'"temp_in_f" : "%.1f",\' \'\' \'temp_f(x)\'#\n#temp_out \'"temp_out_c" : "%.1f",\'#\n#temp_out \'"temp_out_f" : "%.1f",\' \'\' \'temp_f(x)\'#\n#calc \'apparent_temp(data["temp_out"],data["hum_out"],data["wind_ave"])\' \'"temp_out_realfeel_c" : "%.1f",\'#\n#calc \'temp_f(apparent_temp(data["temp_out"],data["hum_out"],data["wind_ave"]))\' \'"temp_out_realfeel_f" : "%.1f",\'#\n#rel_pressure \'"pressure_rel_hpa" : "%.1f",\'#\n#rel_pressure \'"pressure_rel_inhg": "%.4f",\' \'\' \'pressure_inhg(x)\'#\n#abs_pressure \'"pressure_abs_hpa" : "%.1f",\'#\n#abs_pressure \'"pressure_abs_inhg": "%.4f",\' \'\' \'pressure_inhg(x)\'#\n#rain \'"rain_mm" : "%.1f",\'#\n#rain \'"rain_in" : "%.2f",\' \'\' \'rain_inch(x)\'#\n#calc \'rain_hour(data)\' \'"rain_last_hour_mm": "%.1f",\'#\n#calc \'rain_inch(rain_hour(data))\' \'"rain_last_hour_in": "%.2f",\'#\n#calc \'rain_24hr(data)\' \'"rain_last_24hours_mm": "%.1f",\'#\n#calc \'rain_inch(rain_24hr(data))\' \'"rain_last_24hours_in": "%.2f",\'#\n#calc \'rain_day(data)\' \'"rain_day_mm": "%.1f",\'#\n#calc \'rain_inch(rain_day(data))\' \'"rain_day_in": "%.2f",\'#\n'
template_format(template)[source]
session()[source]

Context manager factory function for a batch of one or more uploads.

This makes it easy to ensure any resources such as an internet connection are properly closed after a batch of uploads. Use the contextlib.contextmanager() decorator when you implement this method.

For a typical example, see the source code of the pywws.service.openweathermap module. If your upload can’t benefit from a session object yield None, as in pywws.service.copy.

upload_data(session, prepared_data={})[source]

Upload one data set to the service.

Every data service class must implement this method.

Parameters:
  • session (object) – the object created by session(). This is typically used to communicate with the server and is automatically closed when a batch of uploads has finished.
  • prepared_data (dict) – a set of key: value pairs to upload. The keys and values must all be text strings.

Comments or questions? Please subscribe to the pywws mailing list http://groups.google.com/group/pywws and let us know.