├── .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 |
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 |
--------------------------------------------------------------------------------