├── .gitignore ├── esphome ├── components │ └── max4409 │ │ ├── __init__.py │ │ ├── sensor.py │ │ ├── max44009.cpp │ │ └── max44009.h └── weatherstation │ ├── UVLightSensor.h │ └── weatherstation.yaml ├── images ├── ws_base.jpg ├── ws_mpuboard.jpg └── ws_anemometer.png ├── README.md └── weewx ├── genmqtt.py └── weewx.conf /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \#*\# -------------------------------------------------------------------------------- /esphome/components/max4409/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/ws_base.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drtaul/hatweaks/HEAD/images/ws_base.jpg -------------------------------------------------------------------------------- /images/ws_mpuboard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drtaul/hatweaks/HEAD/images/ws_mpuboard.jpg -------------------------------------------------------------------------------- /images/ws_anemometer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/drtaul/hatweaks/HEAD/images/ws_anemometer.png -------------------------------------------------------------------------------- /esphome/components/max4409/sensor.py: -------------------------------------------------------------------------------- 1 | import esphome.codegen as cg 2 | import esphome.config_validation as cv 3 | from esphome.components import i2c, sensor 4 | from esphome.const import CONF_ID, UNIT_LUX, ICON_BRIGHTNESS_5 5 | 6 | DEPENDENCIES = ['i2c'] 7 | 8 | max44009_ns = cg.esphome_ns.namespace('max44009') 9 | 10 | MAX44009Sensor = max44009_ns.class_('MAX44009Sensor', sensor.Sensor, cg.PollingComponent, i2c.I2CDevice) 11 | 12 | 13 | CONFIG_SCHEMA = sensor.sensor_schema(UNIT_LUX, ICON_BRIGHTNESS_5, 1).extend({ 14 | cv.GenerateID(): cv.declare_id(MAX44009Sensor) 15 | }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x4a)) 16 | 17 | 18 | def to_code(config): 19 | var = cg.new_Pvariable(config[CONF_ID]) 20 | yield cg.register_component(var, config) 21 | yield i2c.register_i2c_device(var, config) 22 | yield sensor.register_sensor(var, config) 23 | 24 | -------------------------------------------------------------------------------- /esphome/weatherstation/UVLightSensor.h: -------------------------------------------------------------------------------- 1 | // https://github.com/esphome/feature-requests/issues/217#issuecomment-583875043 2 | #include "esphome.h" 3 | #include "SparkFun_VEML6075_Arduino_Library.h" 4 | 5 | class VEML6075CustomSensor : public PollingComponent, public Sensor { 6 | public: 7 | VEML6075 uv = VEML6075(); 8 | 9 | Sensor *uva_sensor = new Sensor(); 10 | Sensor *uvb_sensor = new Sensor(); 11 | Sensor *uvindex_sensor = new Sensor(); 12 | 13 | VEML6075CustomSensor() : PollingComponent(15000) {} 14 | void setup() override { 15 | Wire.begin(); 16 | uv.begin(); 17 | uv.setIntegrationTime(VEML6075::IT_100MS); 18 | } 19 | 20 | void update() override { 21 | float uva = uv.uva(); 22 | float uvb = uv.uvb(); 23 | float index = uv.index(); 24 | ESP_LOGD("custom", "The value of sensor uva is: %.0f", uva); 25 | ESP_LOGD("custom", "The value of sensor uvb is: %.0f", uvb); 26 | ESP_LOGD("custom", "The calculated value of UV index is: %.0f", index); 27 | //publish_state(uva); 28 | uva_sensor->publish_state(uva); 29 | uvb_sensor->publish_state(uvb); 30 | uvindex_sensor->publish_state(index); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /esphome/components/max4409/max44009.cpp: -------------------------------------------------------------------------------- 1 | #include "max44009.h" 2 | #include "esphome/core/log.h" 3 | 4 | namespace esphome { 5 | namespace max44009 { 6 | 7 | static const char *TAG = "max44009.sensor"; 8 | 9 | 10 | void MAX44009Sensor::setup() { 11 | ESP_LOGCONFIG(TAG, "Setting up Max44009..."); 12 | } 13 | void MAX44009Sensor::dump_config() { 14 | ESP_LOGCONFIG(TAG, "MAX44009:"); 15 | LOG_I2C_DEVICE(this); 16 | } 17 | 18 | void MAX44009Sensor::update() { 19 | // Enable sensor 20 | ESP_LOGV(TAG, "accessing lux data"); 21 | float lx = read_lux(); 22 | this->publish_state(lx); 23 | this->status_clear_warning(); 24 | } 25 | 26 | float MAX44009Sensor::read_lux() { 27 | uint8_t dhi, dlo; 28 | float val = 0; 29 | if (read_byte(MAX44009_LUX_READING_HIGH, &dhi)) 30 | { 31 | if (read_byte(MAX44009_LUX_READING_LOW, &dlo)) 32 | { 33 | uint8_t e = dhi >> 4; 34 | if (e == 0x0F) 35 | { 36 | ESP_LOGE(TAG, "OVERFLOW ERROR"); 37 | val = MAX44009_ERROR_OVERFLOW; 38 | this->status_set_warning(); 39 | } 40 | else 41 | { 42 | uint32_t m = ((dhi & 0x0F) << 4) + (dlo & 0x0F); 43 | m <<= e; 44 | val = m * 0.045; 45 | } 46 | } 47 | else 48 | { 49 | ESP_LOGE(TAG, "READ LOW BYTE ERROR"); 50 | val = MAX44009_ERROR_LOW_BYTE; 51 | this->status_set_warning(); 52 | } 53 | } 54 | else 55 | { 56 | ESP_LOGE(TAG, "READ HIGH BYTE ERROR"); 57 | val = MAX44009_ERROR_HIGH_BYTE; 58 | this->status_set_warning(); 59 | } 60 | return val; 61 | } 62 | 63 | } // namespace max44009 64 | } // namespace esphome 65 | -------------------------------------------------------------------------------- /esphome/components/max4409/max44009.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "esphome/core/component.h" 4 | #include "esphome/components/sensor/sensor.h" 5 | #include "esphome/components/i2c/i2c.h" 6 | 7 | namespace esphome { 8 | namespace max44009 { 9 | 10 | enum MAX44009Constants { 11 | MAX44009_DEFAULT_ADDRESS = 0x4A, 12 | MAX44009_ALT_ADDRESS = 0x4B, 13 | MAX44009_OK = 0, 14 | MAX44009_ERROR_WIRE_REQUEST = -10, 15 | MAX44009_ERROR_OVERFLOW = -20, 16 | MAX44009_ERROR_HIGH_BYTE = -30, 17 | MAX44009_ERROR_LOW_BYTE = -31, 18 | }; 19 | 20 | enum MAX44009Registers { 21 | MAX44009_INTERRUPT_STATUS = 0x00, 22 | MAX44009_INTERRUPT_ENABLE = 0x01, 23 | MAX44009_CONFIGURATION = 0x02, 24 | MAX44009_LUX_READING_HIGH = 0x03, 25 | MAX44009_LUX_READING_LOW = 0x04, 26 | MAX44009_THRESHOLD_HIGH = 0x05, 27 | MAX44009_THRESHOLD_LOW = 0x06, 28 | MAX44009_THRESHOLD_TIMER = 0x07, 29 | }; 30 | 31 | enum MAX44009CfgMasks { 32 | MAX44009_CFG_CONTINUOUS = 0x80, 33 | MAX44009_CFG_MANUAL = 0x40, 34 | MAX44009_CFG_CDR = 0x08, 35 | MAX44009_CFG_TIMER = 0x07, 36 | }; 37 | 38 | 39 | /** Provide support for MAX44009 i2c ambient light sensor 40 | * Two key features of the IC analog design are its ultra-low 41 | * current consumption (typically 0.65µA) and an extremely 42 | * wide dynamic light range that extends from 0.045 lux to 43 | * 188,000 lux—more than a 4,000,000 to 1 range. 44 | */ 45 | class MAX44009Sensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { 46 | public: 47 | void setup() override; 48 | void dump_config() override; 49 | void update() override; 50 | protected: 51 | float read_lux(); 52 | }; 53 | 54 | } // namespace max44009 55 | } // namespace esphome 56 | -------------------------------------------------------------------------------- /esphome/weatherstation/weatherstation.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | display_name: ws 3 | 4 | esphome: 5 | name: weatherstation 6 | platform: ESP8266 7 | board: d1_mini_pro 8 | includes: 9 | - UVLightSensor.h 10 | libraries: 11 | - "https://github.com/sparkfun/SparkFun_VEML6075_Arduino_Library" 12 | 13 | wifi: 14 | ssid: "charlottesweb_iot" 15 | password: "XXXXXXXXXXXX" 16 | reboot_timeout: 5min 17 | 18 | captive_portal: 19 | 20 | # Enable logging 21 | logger: 22 | 23 | # Enable Home Assistant API 24 | api: 25 | 26 | ota: 27 | 28 | status_led: 29 | pin: 30 | number: GPIO2 31 | inverted: True 32 | 33 | 34 | i2c: 35 | sda: 4 36 | scl: 5 37 | scan: True 38 | id: bus_a 39 | frequency: 10kHz 40 | 41 | sensor: 42 | - platform: bme280 43 | temperature: 44 | id: "bme280_temperature" 45 | oversampling: 16x 46 | pressure: 47 | id: "bme280_pressure" 48 | humidity: 49 | name: ${display_name} Humi 50 | address: 0x76 51 | i2c_id: bus_a 52 | update_interval: 10s 53 | - platform: pulse_counter 54 | id: tipping_bucket 55 | pin: 56 | number: GPIO12 57 | inverted: True 58 | name: ${display_name} Rain 59 | internal_filter: 1ms 60 | unit_of_measurement: "in/min" 61 | accuracy_decimals: 2 62 | filters: 63 | - multiply: 0.0102362 64 | # - platform: integration 65 | # name: "Accum Rainfall" 66 | # sensor: tipping_bucket 67 | # time_unit: min 68 | - platform: pulse_counter 69 | id: anemometer 70 | name: ${display_name} Wind 71 | pin: 72 | number: GPIO13 73 | inverted: True 74 | unit_of_measurement: mph 75 | filters: 76 | - multiply: 0.0535056 77 | update_interval: 10s 78 | - platform: uptime 79 | name: ${display_name} Uptime 80 | - platform: wifi_signal 81 | name: ${display_name} WiFi Signal 82 | update_interval: 60s 83 | - platform: adc 84 | pin: A0 85 | name: ${display_name} Battery Level 86 | filters: 87 | - lambda: return ((x-.465)/.317) * 100; 88 | unit_of_measurement: "%" 89 | update_interval: 60s 90 | - platform: sht3xd 91 | temperature: 92 | name: ${display_name} Temp2 93 | filters: 94 | - lambda: return x * (9.0/5.0) + 32.0; 95 | unit_of_measurement: "°F" 96 | humidity: 97 | name: ${display_name} Relative Humity 98 | id: sht31d_humity 99 | address: 0x44 100 | i2c_id: bus_a 101 | update_interval: 10s 102 | - platform: template 103 | name: ${display_name} Pres 104 | icon: 'mdi:gauge' 105 | lambda: |- 106 | const float STANDARD_ALTITUDE = 140.0; 107 | const float HPA2INHG = 0.02953; 108 | return (id(bme280_pressure).state / powf(1 - ((0.0065 * STANDARD_ALTITUDE) / (id(bme280_temperature).state + (0.0065 * STANDARD_ALTITUDE) + 273.15)), 5.257)) * HPA2INHG; 109 | unit_of_measurement: "in-hg" 110 | update_interval: 10s 111 | - platform: template 112 | name: ${display_name} Temp 113 | lambda: |- 114 | return id(bme280_temperature).state * (9.0/5.0) + 32.0; 115 | unit_of_measurement: "°F" 116 | update_interval: 10s 117 | - platform: custom 118 | lambda: |- 119 | auto veml6075 = new VEML6075CustomSensor(); 120 | App.register_component(veml6075); 121 | return {veml6075->uva_sensor, veml6075->uvb_sensor, veml6075->uvindex_sensor}; 122 | sensors: 123 | - name: "UVA" 124 | id: zelva_uva 125 | unit_of_measurement: "µW/cm²" 126 | accuracy_decimals: 1 127 | - name: "UVB" 128 | id: zelva_uvb 129 | unit_of_measurement: "µW/cm²" 130 | accuracy_decimals: 1 131 | - name: "UVIndex" 132 | id: zelva_uvi 133 | accuracy_decimals: 1 134 | - platform max44009 135 | name: "Ambient Light Sensor" 136 | address: 0x4B -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adding a DIY weatherstation to Home Assistant 2 | 3 | I recently built a remote weatherstation with the core MPU a 8266 4 | running ESPHome. This weatherstation currently pushes the following 5 | measurements into my HomeAssistant system via the HA/ESPHome API. 6 | Basic direction for this weatherstation came from [digiblur](https://www.youtube.com/watch?v=VUqOIPVbeF0). 7 | 8 | * Outside temperature using BME280 9 | * Barometric pressure using BME280 10 | * Outside humidity using BME280 11 | * Outside temperature using SHT31-D 12 | * Outside humidity using SHT31-D 13 | * Hacked La Crosse TX58UN tipping bucket raingauge (ebay purchase) 14 | * Hacked La Crosse LTV-W1 Wind Speed Sensor (ebay purchase) 15 | * UV Index using VEML6075 UV 16 | * Ambient Light using MAX44009 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
WS WS2 WS3
25 | 26 | This is a remote unattended weather station. Thus included the following 27 | to allow it to be standalone albeit it does connect into my local wifi. 28 | 29 | * Wemo D1 mini pro with exernal antenna 30 | * 18650 batter with P4056 based charging circuit connected to 1.5 watt solar panel. 31 | 32 | The [BME280 has known issues with reliably reporting humity reading](https://thecavepearlproject.org/2015/06/15/developing-an-arduino-based-weather-station/). 33 | 34 | DHT11 and DHT12 is not trusted in general absolutely. 35 | AHT10 and AHT15 – also not trusted, slow and inaccurate, but maybe better than DHTxx 36 | AM2320 – relatively not that bad (in compare to DHT and AHT) 37 | BME280 and BME680 is always higher temperature and lower humidity (I suspect self-heating) I think those sensors are not for uncalibrated DIY projects) 38 | HDC1080 – wrong (high) humidity 39 | HDC2080 – wrong (high) temperature 40 | SHT2x – OK 41 | SHT3x – OK 42 | SHTC1 and SHTC3 – OK 43 | SHT85 – Perfect 44 | 45 | This is why the SHT31-D is included. It also provides a double reference for 46 | measuring the temperature. Experience with other commonly using temperature 47 | sensors have proven to be much less accurate e.g. DHT22. 48 | 49 | ## Weewx 50 | 51 | As part of this project, a local [weewx](http://weewx.com/) server was 52 | set up alongside Home Assistant on a UNRAID based server using Docker. 53 | 54 | Home Assistant automations were created to forward the weather station 55 | sensor data to MQTT. A simple generic weewx driver was written to 56 | transfer directly from the MQTT topics into the weewx loop packet. 57 | By using MQTT topic names that come directly from weewx, the driver 58 | is small and simple. 59 | 60 | ## Unsupported Sensors 61 | 62 | At the time of this writing, ESPHome supports neither the *VEML6075* or the *MAX44009*. 63 | 64 | ### MAX44009 65 | A native ESPHome component was written for the MAX44009 sensor given the [difficulties 66 | people were having](https://github.com/esphome/feature-requests/issues/29) incorporating an external arduino library. This native component has NOT been submitted to ESPHome for merging as it is 67 | incomplete. The code to read and calculate the LUX reading came from [dantudose github](https://github.com/dantudose/MAX44009). 68 | 69 | Adding the native code for this sensor under the ESPHome directory was not obvious besides submitting 70 | a pull request to have the component added to ESHome's github. Turns out you can create a directory 71 | under the ESPHome root directory named *custom_components*. Now copy the max44009 directory under 72 | the custom_components directory. 73 | 74 | 75 | ### VEM6075 76 | The VEML6075 was added as a custom component in the *weatherstation.yaml* 77 | configuration file. This required writing the *UVLightSensor.h* and adding the *includes* and *libraries* 78 | list items in the weatherstation.yaml file. 79 | -------------------------------------------------------------------------------- /weewx/genmqtt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | """ 4 | Generic MQTT Driver for WEEWX 5 | Requires the paho mqtt client package to listen on publications from specified MQTT Server. 6 | Reference the weewx.conf file section for this driver to identify the configuration parameters. 7 | poll_interval = 10 8 | host = mqtt-server-hostname 9 | username = needuser 10 | password = needpassword 11 | topic = pws/+ 12 | 13 | Note the base topic is 'pws'. The subtopics must be compliant with the 14 | standard generic weewx parameter names (listed in the weewx.conf file). 15 | Listed here is an excerpt of the parameters that have been tested. 16 | barometer = Barometer 17 | dewpoint = Dew Point 18 | ET = ET 19 | outHumidity = Humidity 20 | outTemp = Outside Temperature 21 | radiation = Radiation 22 | rain = Rain 23 | rainRate = Rain Rate 24 | UV = UV Index 25 | windSpeed = Wind Speed 26 | 27 | An example of publishing from Home Assistant Automation: 28 | 29 | automation: 30 | - alias: "Publish BME280 Data" 31 | trigger: 32 | platform: state 33 | entity_id: 34 | - sensor.ws_temp 35 | - sensor.ws_relative_humity 36 | - sensor.ws_pres 37 | action: 38 | - service: mqtt.publish 39 | data_template: 40 | topic: 'pws/outTemp' 41 | payload: "{{ states('sensor.ws_temp')|float }}" 42 | - service: mqtt.publish 43 | data_template: 44 | topic: 'pws/outHumidity' 45 | payload: "{{ states('sensor.ws_relative_humity')|float }}" 46 | - service: mqtt.publish 47 | data_template: 48 | topic: 'pws/barometer' 49 | payload: "{{ states('sensor.ws_pres')|float }}" 50 | 51 | 52 | """ 53 | import logging 54 | import sys 55 | import time 56 | import queue 57 | import paho.mqtt.client as mqtt 58 | 59 | import weeutil.logger 60 | import weeutil.weeutil 61 | import weewx.wxformulas 62 | import weewx.drivers 63 | 64 | # use standard python logging infrastructure 65 | # reviewing weeutil.logger, weewx is designed to work with this 66 | # visit the weewx.conf file, set debug=1 to enable debug level logs 67 | log = logging.getLogger(__name__) 68 | 69 | # driver name must match the section title in weewx.conf 70 | DRIVER_NAME = 'GenMqtt' 71 | DRIVER_VERSION = "0.1" 72 | 73 | # required to integrate into the weewx framework 74 | def loader(config_dict, engine): 75 | return GenericMqttDriver(**config_dict[DRIVER_NAME]) 76 | 77 | 78 | class GenericMqttDriver(weewx.drivers.AbstractDevice): 79 | """Define Class for Generic MQTT Driver deriving from weewx base class 80 | This implementation is based off of the wxMesh driver. Unlike wxMesh 81 | this driver does not allow mapping from one label space to another. 82 | 83 | This driver is a minimal implementation and only implements a minimal 84 | set of class methods as defined by the AbstraceDevice class. 85 | """ 86 | 87 | def __init__(self, **stn_dict): 88 | """ Constructor will extract the required parameters 89 | and connect to the MQTT server 90 | """ 91 | self.host = stn_dict.get('host', 'localhost') 92 | self.topic = stn_dict.get('topic', 'weather') 93 | self.username = stn_dict.get('username', 'no default') 94 | self.password = stn_dict.get('password', 'no default') 95 | self.client_id = stn_dict.get('client', 'wxclient') # MQTT client id - adjust as desired 96 | 97 | # how often to poll the weather data file, seconds 98 | self.poll_interval = float(stn_dict.get('poll_interval', 5.0)) 99 | 100 | log.info('driver version is %s' % DRIVER_VERSION) 101 | 102 | log.info("MQTT host is %s" % self.host) 103 | log.info("MQTT topic is %s" % self.topic) 104 | log.info("MQTT client is %s" % self.client_id) 105 | log.info("polling interval is %s" % self.poll_interval) 106 | 107 | self.mqtt_queue = queue.Queue() 108 | self.connected = False 109 | 110 | self.client = mqtt.Client(client_id=self.client_id, protocol=mqtt.MQTTv31) 111 | 112 | # TODO - need some reconnect on disconnect logic 113 | #self.client.on_disconnect = self.on_disconnect 114 | self.client.on_message = self.on_message 115 | 116 | self.client.username_pw_set(self.username, self.password) 117 | self.client.connect(self.host, 1883, 60) 118 | 119 | log.debug("Connected") 120 | self.client.loop_start() 121 | self.client.subscribe(self.topic, qos=1) 122 | 123 | @property 124 | def hardware_name(self): 125 | return DRIVER_NAME 126 | 127 | def on_message(self, client, userdata, msg): 128 | """ callback for when a PUBLISH message is received from the MQTT server 129 | each message is queued for processing by the genLoopPackets method. 130 | """ 131 | self.mqtt_queue.put([msg.topic, float(msg.payload)]) 132 | log.debug("Added to queue of %d message %s:%s" % (self.mqtt_queue.qsize(), msg.topic, msg.payload)) 133 | 134 | def on_connect(self, client, userdata, rc): 135 | if rc == 0: 136 | self.connected = True 137 | 138 | def closePort(self): 139 | self.client.disconnect() 140 | self.client.loop_stop() 141 | 142 | 143 | def genLoopPackets(self): 144 | """ Build the basic loop packet for the weewx framework. This method will create a 145 | new looppacket (python dictionary) with the units and dateTime entries. It will 146 | add additional entries as is available in the processing queue (published messages 147 | received from MQTT). 148 | 149 | No validation is done on the topics received from MQTT. Only success path testing 150 | has been done at this time. 151 | """ 152 | _packet = None 153 | while True: 154 | while not self.mqtt_queue.empty(): 155 | log.debug("Processing queue of %d entries" % self.mqtt_queue.qsize()) 156 | if _packet is None: 157 | _packet = {'usUnits': weewx.US, 'dateTime': int(time.time())} 158 | while True: 159 | try: 160 | topic = self.mqtt_queue.get_nowait() 161 | except queue.Empty: 162 | break 163 | log.debug("processing topic : %s" % (topic)) 164 | key = topic[0].split('/')[1] 165 | value = topic[1] 166 | _packet[key] = value 167 | 168 | if _packet is not None: 169 | if 'outTemp' in _packet and 'outHumidity' in _packet: 170 | _packet['dewpoint'] = weewx.wxformulas.dewpointC(_packet['outTemp'], _packet['outHumidity']) 171 | log.debug("yielding loop packet with %d entries" % (len(_packet))) 172 | loop_packet = _packet 173 | _packet = None 174 | yield loop_packet 175 | else: 176 | log.debug("sleeping for %d secs" % (self.poll_interval)) 177 | time.sleep(self.poll_interval) 178 | 179 | 180 | -------------------------------------------------------------------------------- /weewx/weewx.conf: -------------------------------------------------------------------------------- 1 | # WEEWX CONFIGURATION FILE 2 | # 3 | # Copyright (c) 2009-2019 Tom Keffer 4 | # See the file LICENSE.txt for your rights. 5 | 6 | ############################################################################## 7 | 8 | # This section is for general configuration information. 9 | 10 | # Set to 1 for extra debug info, otherwise comment it out or set to zero 11 | debug = 0 12 | 13 | # Root directory of the weewx data file hierarchy for this station 14 | WEEWX_ROOT = /home/weewx 15 | 16 | # Whether to log successful operations 17 | log_success = True 18 | 19 | # Whether to log unsuccessful operations 20 | log_failure = True 21 | 22 | # How long to wait before timing out a socket (FTP, HTTP) connection 23 | socket_timeout = 20 24 | 25 | # Do not modify this. It is used when installing and updating weewx. 26 | version = 4.0.0 27 | 28 | ############################################################################## 29 | 30 | # This section is for information about the station. 31 | 32 | [Station] 33 | 34 | # Description of the station location 35 | location = "Youngsville, North Carolina" 36 | 37 | # Latitude in decimal degrees. Negative for southern hemisphere 38 | latitude = 36.030542 39 | # Longitude in decimal degrees. Negative for western hemisphere. 40 | longitude = -78.528753 41 | 42 | # Altitude of the station, with unit it is in. This is downloaded from 43 | # from the station if the hardware supports it. 44 | altitude = 140, meter # Choose 'foot' or 'meter' for unit 45 | 46 | # Set to type of station hardware. There must be a corresponding stanza 47 | # in this file with a 'driver' parameter indicating the driver to be used. 48 | station_type = GenMqtt 49 | 50 | # If you have a website, you may specify an URL 51 | #station_url = http://www.example.com 52 | 53 | # The start of the rain year (1=January; 10=October, etc.). This is 54 | # downloaded from the station if the hardware supports it. 55 | rain_year_start = 1 56 | 57 | # Start of week (0=Monday, 6=Sunday) 58 | week_start = 6 59 | 60 | ############################################################################## 61 | 62 | [GenMqtt] 63 | poll_interval = 10 64 | host = dell-t7810 65 | username = needuser 66 | password = needpassword 67 | topic = pws/+ 68 | 69 | # The start time. Format is YYYY-mm-ddTHH:MM. If not specified, the default 70 | # is to use the present time. 71 | #start = 2011-01-01T00:00 72 | 73 | # The driver to use: 74 | driver = weewx.drivers.genmqtt 75 | 76 | ############################################################################## 77 | 78 | # This section is for uploading data to Internet sites 79 | 80 | [StdRESTful] 81 | 82 | [[StationRegistry]] 83 | # To register this weather station with weewx, set this to true 84 | register_this_station = false 85 | 86 | [[AWEKAS]] 87 | # This section is for configuring posts to AWEKAS. 88 | 89 | # If you wish to do this, set the option 'enable' to true, 90 | # and specify a username and password. 91 | # To guard against parsing errors, put the password in quotes. 92 | enable = false 93 | username = replace_me 94 | password = replace_me 95 | 96 | [[CWOP]] 97 | # This section is for configuring posts to CWOP. 98 | 99 | # If you wish to do this, set the option 'enable' to true, 100 | # and specify the station ID (e.g., CW1234). 101 | enable = false 102 | station = replace_me 103 | 104 | # If this is an APRS (radio amateur) station, uncomment 105 | # the following and replace with a passcode (e.g., 12345). 106 | #passcode = replace_me (APRS stations only) 107 | 108 | [[PWSweather]] 109 | # This section is for configuring posts to PWSweather.com. 110 | 111 | # If you wish to do this, set the option 'enable' to true, 112 | # and specify a station and password. 113 | # To guard against parsing errors, put the password in quotes. 114 | enable = true 115 | station = KNCYOUNG50 116 | password = XXXXXXX 117 | 118 | [[WOW]] 119 | # This section is for configuring posts to WOW. 120 | 121 | # If you wish to do this, set the option 'enable' to true, 122 | # and specify a station and password. 123 | # To guard against parsing errors, put the password in quotes. 124 | enable = false 125 | station = replace_me 126 | password = replace_me 127 | 128 | [[Wunderground]] 129 | # This section is for configuring posts to the Weather Underground. 130 | 131 | # If you wish to do this, set the option 'enable' to true, 132 | # and specify a station (e.g., 'KORHOODR3') and password. 133 | # To guard against parsing errors, put the password in quotes. 134 | enable = true 135 | station = KNCYOUNG50 136 | password = XXXXXXX 137 | 138 | # If you plan on using wunderfixer, set the following 139 | # to your API key: 140 | api_key = af5cd8b6ac0240d69cd8b6ac0260d6a1 141 | 142 | # Set the following to True to have weewx use the WU "Rapidfire" 143 | # protocol. Not all hardware can support it. See the User's Guide. 144 | rapidfire = False 145 | [[MQTT]] 146 | server_url = INSERT_SERVER_URL_HERE 147 | 148 | ############################################################################## 149 | 150 | # This section specifies what reports, using which skins, to generate. 151 | 152 | [StdReport] 153 | 154 | # Where the skins reside, relative to WEEWX_ROOT 155 | SKIN_ROOT = skins 156 | 157 | # Where the generated reports should go, relative to WEEWX_ROOT 158 | HTML_ROOT = /data/public_html 159 | 160 | # The database binding indicates which data should be used in reports. 161 | data_binding = wx_binding 162 | 163 | # Whether to log a successful operation 164 | log_success = True 165 | 166 | # Whether to log an unsuccessful operation 167 | log_failure = False 168 | 169 | # Each of the following subsections defines a report that will be run. 170 | # See the customizing guide to change the units, plot types and line 171 | # colors, modify the fonts, display additional sensor data, and other 172 | # customizations. Many of those changes can be made here by overriding 173 | # parameters, or by modifying templates within the skin itself. 174 | 175 | [[SeasonsReport]] 176 | # The SeasonsReport uses the 'Seasons' skin, which contains the 177 | # images, templates and plots for the report. 178 | skin = Seasons 179 | enable = true 180 | 181 | [[SmartphoneReport]] 182 | # The SmartphoneReport uses the 'Smartphone' skin, and the images and 183 | # files are placed in a dedicated subdirectory. 184 | skin = Smartphone 185 | enable = false 186 | HTML_ROOT = public_html/smartphone 187 | 188 | [[MobileReport]] 189 | # The MobileReport uses the 'Mobile' skin, and the images and files 190 | # are placed in a dedicated subdirectory. 191 | skin = Mobile 192 | enable = false 193 | HTML_ROOT = public_html/mobile 194 | 195 | [[StandardReport]] 196 | # This is the old "Standard" skin. By default, it is not enabled. 197 | skin = Standard 198 | enable = false 199 | 200 | [[FTP]] 201 | # FTP'ing the results to a webserver is treated as just another report, 202 | # albeit one with an unusual report generator! 203 | skin = Ftp 204 | 205 | # If you wish to use FTP, set "enable" to "true", then 206 | # fill out the next four lines. 207 | # Use quotes around passwords to guard against parsing errors. 208 | enable = false 209 | user = replace_me 210 | password = replace_me 211 | server = replace_me # The ftp server name, e.g, www.myserver.org 212 | path = replace_me # The destination directory, e.g., /weather 213 | 214 | # Set to True for an FTP over TLS (FTPS) connection. Not all servers 215 | # support this. 216 | secure_ftp = False 217 | 218 | # To upload files from something other than what HTML_ROOT is set 219 | # to above, specify a different HTML_ROOT here. 220 | #HTML_ROOT = public_html 221 | 222 | # Most FTP servers use port 21 223 | port = 21 224 | 225 | # Set to 1 to use passive mode, zero for active mode 226 | passive = 1 227 | 228 | [[RSYNC]] 229 | # rsync'ing to a webserver is treated as just another report 230 | skin = Rsync 231 | 232 | # If you wish to use rsync, you must configure passwordless ssh using 233 | # public/private key authentication from the user account that weewx 234 | # runs to the user account on the remote machine where the files 235 | # will be copied. 236 | # 237 | # If you wish to use rsync, set "enable" to "true", then 238 | # fill out server, user, and path. 239 | # The server should appear in your .ssh/config file. 240 | # The user is the username used in the identity file. 241 | # The path is the destination directory, such as /var/www/html/weather. 242 | # Be sure that the user has write permissions on the destination! 243 | enable = false 244 | server = replace_me 245 | user = replace_me 246 | path = replace_me 247 | 248 | # To upload files from something other than what HTML_ROOT is set 249 | # to above, specify a different HTML_ROOT here. 250 | #HTML_ROOT = public_html 251 | 252 | # Rsync can be configured to remove files from the remote server if 253 | # they don't exist under HTML_ROOT locally. USE WITH CAUTION: if you 254 | # make a mistake in the remote path, you could could unintentionally 255 | # cause unrelated files to be deleted. Set to 1 to enable remote file 256 | # deletion, zero to allow files to accumulate remotely. 257 | delete = 0 258 | 259 | #### 260 | 261 | # Various options for customizing your reports. 262 | 263 | [[Defaults]] 264 | 265 | [[[Units]]] 266 | 267 | # The following section sets what unit to use for each unit group. 268 | # NB: The unit is always in the singular. I.e., 'mile_per_hour', 269 | # NOT 'miles_per_hour' 270 | [[[[Groups]]]] 271 | 272 | group_altitude = foot # Options are 'foot' or 'meter' 273 | group_degree_day = degree_F_day # Options are 'degree_F_day' or 'degree_C_day' 274 | group_distance = mile # Options are 'mile' or 'km' 275 | group_pressure = inHg # Options are 'inHg', 'mmHg', 'mbar', or 'hPa' 276 | group_rain = inch # Options are 'inch', 'cm', or 'mm' 277 | group_rainrate = inch_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour' 278 | group_speed = mile_per_hour # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second' 279 | group_speed2 = mile_per_hour2 # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2' 280 | group_temperature = degree_F # Options are 'degree_F' or 'degree_C' 281 | 282 | # The following section sets the formatting for each type of unit. 283 | [[[[StringFormats]]]] 284 | 285 | centibar = %.0f 286 | cm = %.2f 287 | cm_per_hour = %.2f 288 | degree_C = %.1f 289 | degree_F = %.1f 290 | degree_compass = %.0f 291 | foot = %.0f 292 | hPa = %.1f 293 | hour = %.1f 294 | inHg = %.3f 295 | inch = %.2f 296 | inch_per_hour = %.2f 297 | km = %.1f 298 | km_per_hour = %.0f 299 | km_per_hour2 = %.1f 300 | knot = %.0f 301 | knot2 = %.1f 302 | mbar = %.1f 303 | meter = %.0f 304 | meter_per_second = %.1f 305 | meter_per_second2 = %.1f 306 | mile = %.1f 307 | mile_per_hour = %.0f 308 | mile_per_hour2 = %.1f 309 | mm = %.1f 310 | mmHg = %.1f 311 | mm_per_hour = %.1f 312 | percent = %.0f 313 | second = %.0f 314 | uv_index = %.1f 315 | volt = %.1f 316 | watt_per_meter_squared = %.0f 317 | NONE = " N/A" 318 | 319 | # The following section overrides the label used for each type of unit 320 | [[[[Labels]]]] 321 | 322 | meter = " meter", " meters" # You may prefer "metre". 323 | day = " day", " days" 324 | hour = " hour", " hours" 325 | minute = " minute", " minutes" 326 | second = " second", " seconds" 327 | NONE = "" 328 | 329 | # The following section sets the format for each time scale. 330 | # The values below will work in every locale, but they may not look 331 | # particularly attractive. 332 | [[[[TimeFormats]]]] 333 | 334 | hour = %H:%M 335 | day = %X 336 | week = %X (%A) 337 | month = %x %X 338 | year = %x %X 339 | rainyear = %x %X 340 | current = %x %X 341 | ephem_day = %X 342 | ephem_year = %x %X 343 | 344 | [[[[Ordinates]]]] 345 | 346 | # Ordinal directions. The last one is for no wind direction 347 | directions = N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW, N/A 348 | 349 | # The following section sets the base temperatures used for the 350 | # calculation of heating, cooling, and growing degree-days. 351 | [[[[DegreeDays]]]] 352 | 353 | # Base temperature for heating days, with unit: 354 | heating_base = 65, degree_F 355 | # Base temperature for cooling days, with unit: 356 | cooling_base = 65, degree_F 357 | # Base temperature for growing days, with unit: 358 | growing_base = 50, degree_F 359 | 360 | # A trend takes a difference across a time period. The following 361 | # section sets the time period, and how big an error is allowed to 362 | # still be counted as the start or end of a period. 363 | [[[[Trend]]]] 364 | 365 | time_delta = 10800 # 3 hours 366 | time_grace = 300 # 5 minutes 367 | 368 | # The labels to be used for each observation type 369 | [[[Labels]]] 370 | 371 | # Set to hemisphere abbreviations suitable for your location: 372 | hemispheres = N, S, E, W 373 | 374 | # Formats to be used for latitude whole degrees, longitude whole 375 | # degrees, and minutes: 376 | latlon_formats = %02d, %03d, %05.2f 377 | 378 | # Generic labels, keyed by an observation type. 379 | [[[[Generic]]]] 380 | barometer = Barometer 381 | dewpoint = Dew Point 382 | ET = ET 383 | heatindex = Heat Index 384 | inHumidity = Inside Humidity 385 | inTemp = Inside Temperature 386 | outHumidity = Humidity 387 | outTemp = Outside Temperature 388 | radiation = Radiation 389 | rain = Rain 390 | rainRate = Rain Rate 391 | UV = UV Index 392 | windDir = Wind Direction 393 | windGust = Gust Speed 394 | windGustDir = Gust Direction 395 | windSpeed = Wind Speed 396 | windchill = Wind Chill 397 | windgustvec = Gust Vector 398 | windvec = Wind Vector 399 | extraTemp1 = Temperature1 400 | extraTemp2 = Temperature2 401 | extraTemp3 = Temperature3 402 | 403 | # Sensor status indicators 404 | 405 | rxCheckPercent = Signal Quality 406 | txBatteryStatus = Transmitter Battery 407 | windBatteryStatus = Wind Battery 408 | rainBatteryStatus = Rain Battery 409 | outTempBatteryStatus = Outside Temperature Battery 410 | inTempBatteryStatus = Inside Temperature Battery 411 | consBatteryVoltage = Console Battery 412 | heatingVoltage = Heating Battery 413 | supplyVoltage = Supply Voltage 414 | referenceVoltage = Reference Voltage 415 | 416 | [[[Almanac]]] 417 | 418 | # The labels to be used for the phases of the moon: 419 | moon_phases = New, Waxing crescent, First quarter, Waxing gibbous, Full, Waning gibbous, Last quarter, Waning crescent 420 | 421 | ############################################################################## 422 | 423 | # This service acts as a filter, converting the unit system coming from 424 | # the hardware to a unit system in the database. 425 | 426 | [StdConvert] 427 | 428 | # The target_unit affects only the unit system in the database. Once 429 | # chosen it cannot be changed without converting the entire database. 430 | # Modification of target_unit after starting weewx will result in 431 | # corrupt data - the database will contain a mix of US and METRIC data. 432 | # 433 | # The value of target_unit does not affect the unit system for 434 | # reporting - reports can display US, Metric, or any combination of units. 435 | # 436 | # In most cases, target_unit should be left as the default: US 437 | # 438 | # In particular, those migrating from a standard wview installation 439 | # should use US since that is what the wview database contains. 440 | 441 | # DO NOT MODIFY THIS VALUE UNLESS YOU KNOW WHAT YOU ARE DOING! 442 | target_unit = US # Options are 'US', 'METRICWX', or 'METRIC' 443 | 444 | ############################################################################## 445 | 446 | # This section can adjust data using calibration expressions. 447 | 448 | [StdCalibrate] 449 | 450 | [[Corrections]] 451 | # For each type, an arbitrary calibration expression can be given. 452 | # It should be in the units defined in the StdConvert section. 453 | # Example: 454 | foo = foo + 0.2 455 | 456 | ############################################################################## 457 | 458 | # This section is for quality control checks. If units are not specified, 459 | # values must be in the units defined in the StdConvert section. 460 | 461 | [StdQC] 462 | 463 | [[MinMax]] 464 | barometer = 26, 32.5, inHg 465 | pressure = 24, 34.5, inHg 466 | outTemp = -40, 120, degree_F 467 | inTemp = 10, 120, degree_F 468 | outHumidity = 0, 100 469 | inHumidity = 0, 100 470 | windSpeed = 0, 120, mile_per_hour 471 | rain = 0, 10, inch 472 | 473 | ############################################################################## 474 | 475 | # This section controls the origin of derived values. 476 | 477 | [StdWXCalculate] 478 | 479 | [[Calculations]] 480 | # How to calculate derived quantities. Possible values are: 481 | # hardware - use the value provided by hardware 482 | # software - use the value calculated by weewx 483 | # prefer_hardware - use value provide by hardware if available, 484 | # otherwise use value calculated by weewx 485 | 486 | pressure = prefer_hardware 487 | altimeter = prefer_hardware 488 | appTemp = prefer_hardware 489 | barometer = prefer_hardware 490 | beaufort = prefer_hardware 491 | cloudbase = prefer_hardware 492 | dewpoint = prefer_hardware 493 | ET = prefer_hardware 494 | heatindex = prefer_hardware 495 | humidex = prefer_hardware 496 | inDewpoint = prefer_hardware 497 | maxSolarRad = prefer_hardware 498 | rainRate = prefer_hardware 499 | windchill = prefer_hardware 500 | windrun = prefer_hardware 501 | 502 | ############################################################################## 503 | 504 | # For hardware that supports it, this section controls how often the 505 | # onboard clock gets updated. 506 | 507 | [StdTimeSynch] 508 | 509 | # How often to check the weather station clock for drift (in seconds) 510 | clock_check = 14400 511 | 512 | # How much it can drift before we will correct it (in seconds) 513 | max_drift = 5 514 | 515 | ############################################################################## 516 | 517 | # This section is for configuring the archive service. 518 | 519 | [StdArchive] 520 | 521 | # If the station hardware supports data logging then the archive interval 522 | # will be downloaded from the station. Otherwise, specify it (in seconds). 523 | archive_interval = 300 524 | 525 | # If possible, new archive records are downloaded from the station 526 | # hardware. If the hardware does not support this, then new archive 527 | # records will be generated in software. 528 | # Set the following to "software" to force software record generation. 529 | record_generation = hardware 530 | 531 | # Whether to include LOOP data in hi/low statistics 532 | loop_hilo = True 533 | 534 | # The data binding used to save archive records 535 | data_binding = wx_binding 536 | 537 | ############################################################################## 538 | 539 | # This section binds a data store to a database. 540 | 541 | [DataBindings] 542 | 543 | [[wx_binding]] 544 | # The database must match one of the sections in [Databases]. 545 | # This is likely to be the only option you would want to change. 546 | database = archive_sqlite 547 | # The name of the table within the database 548 | table_name = archive 549 | # The manager handles aggregation of data for historical summaries 550 | manager = weewx.manager.DaySummaryManager 551 | # The schema defines the structure of the database. 552 | # It is *only* used when the database is created. 553 | schema = schemas.wview_extended.schema 554 | 555 | ############################################################################## 556 | 557 | # This section defines various databases. 558 | 559 | [Databases] 560 | 561 | # A SQLite database is simply a single file 562 | [[archive_sqlite]] 563 | database_name = weewx.sdb 564 | database_type = SQLite 565 | 566 | # MySQL 567 | [[archive_mysql]] 568 | database_name = weewx 569 | database_type = MySQL 570 | 571 | ############################################################################## 572 | 573 | # This section defines defaults for the different types of databases. 574 | 575 | [DatabaseTypes] 576 | 577 | # Defaults for SQLite databases 578 | [[SQLite]] 579 | driver = weedb.sqlite 580 | # Directory in which the database files are located 581 | SQLITE_ROOT = /data 582 | 583 | # Defaults for MySQL databases 584 | [[MySQL]] 585 | driver = weedb.mysql 586 | # The host where the database is located 587 | host = localhost 588 | # The user name for logging in to the host 589 | user = weewx 590 | # The password for the user name (quotes guard against parsing errors) 591 | password = weewx 592 | 593 | ############################################################################## 594 | 595 | # This section configures the internal weewx engine. 596 | 597 | [Engine] 598 | 599 | [[Services]] 600 | # This section specifies the services that should be run. They are 601 | # grouped by type, and the order of services within each group 602 | # determines the order in which the services will be run. 603 | prep_services = weewx.engine.StdTimeSynch 604 | data_services = , 605 | process_services = weewx.engine.StdConvert, weewx.engine.StdCalibrate, weewx.engine.StdQC, weewx.wxservices.StdWXCalculate 606 | archive_services = weewx.engine.StdArchive 607 | restful_services = weewx.restx.StdStationRegistry, weewx.restx.StdWunderground, weewx.restx.StdPWSweather, weewx.restx.StdCWOP, weewx.restx.StdWOW, weewx.restx.StdAWEKAS, user.mqtt.MQTT 608 | report_services = weewx.engine.StdPrint, weewx.engine.StdReport 609 | --------------------------------------------------------------------------------