From 9d5a6cbdecc4c74f54602912122d6546d904b60c Mon Sep 17 00:00:00 2001 From: Tom Mitchell <52498+tomdotorg@users.noreply.github.com> Date: Sat, 23 Nov 2024 05:57:55 -0500 Subject: [PATCH] v5.1.0-5 - update examples --- .gitignore | 1 + examples/mounts/skins/Belchertown/about.inc | 13 + .../mounts/skins/Belchertown/footer.html.tmpl | 19 + examples/mounts/skins/Belchertown/graphs.conf | 414 ++++++++++++++++++ .../Highcharts_Belchertown/json/day.json.tmpl | 84 ++++ .../json/month.json.tmpl | 84 ++++ .../json/week.json.tmpl | 84 ++++ .../json/year.json.tmpl | 84 ++++ .../skins/Highcharts_Belchertown/skin.conf | 231 ++++++++++ extensions/weewx-mqtt.zip | Bin 0 -> 8256 bytes run-test.sh | 2 +- 11 files changed, 1015 insertions(+), 1 deletion(-) create mode 100644 examples/mounts/skins/Belchertown/about.inc create mode 100644 examples/mounts/skins/Belchertown/footer.html.tmpl create mode 100644 examples/mounts/skins/Belchertown/graphs.conf create mode 100644 examples/mounts/skins/Highcharts_Belchertown/json/day.json.tmpl create mode 100644 examples/mounts/skins/Highcharts_Belchertown/json/month.json.tmpl create mode 100644 examples/mounts/skins/Highcharts_Belchertown/json/week.json.tmpl create mode 100644 examples/mounts/skins/Highcharts_Belchertown/json/year.json.tmpl create mode 100644 examples/mounts/skins/Highcharts_Belchertown/skin.conf create mode 100644 extensions/weewx-mqtt.zip diff --git a/.gitignore b/.gitignore index 0d33b7d..b325f09 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ docker-weewx.code-workspace /weewx.conf /archive/weewx.sdb /keys/ +/dist/ diff --git a/examples/mounts/skins/Belchertown/about.inc b/examples/mounts/skins/Belchertown/about.inc new file mode 100644 index 0000000..762252e --- /dev/null +++ b/examples/mounts/skins/Belchertown/about.inc @@ -0,0 +1,13 @@ +
+
+

Welcome to Beverly Cove!

+

This is just a hobby website I use to learn new software architectures, technologies, and techniques. If you have + suggestions or want to see something different, feel free to suggest: tom@tom.org +

+ +
diff --git a/examples/mounts/skins/Belchertown/footer.html.tmpl b/examples/mounts/skins/Belchertown/footer.html.tmpl new file mode 100644 index 0000000..db6d9d0 --- /dev/null +++ b/examples/mounts/skins/Belchertown/footer.html.tmpl @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/examples/mounts/skins/Belchertown/graphs.conf b/examples/mounts/skins/Belchertown/graphs.conf new file mode 100644 index 0000000..78a3868 --- /dev/null +++ b/examples/mounts/skins/Belchertown/graphs.conf @@ -0,0 +1,414 @@ +# This is the Belchertown skin charting system which utilizes Highcharts to display the chart data. +# +# PLEASE READ THE CHARTS WIKI! A lot of information is there and it will help you! +# It is located here: https://github.com/poblabs/weewx-belchertown/wiki/Belchertown-Charts-Documentation +# +# Caution! +# The more charts you have, the slower things can become. This is especially true at the YEAR level. These are interactive charts which have to build plot points from the database on every archive interval. This could result in large file sizes to generate, and for your website visitors to download. You're welcome to customize as many charts as you want, but be warned things could slow down if you do too much! +# The defaults in this skin have proven to be a good baseline for the number of charts and options without overwhelming your system. +# +# Overview of options: +# A timespan refers to "day", "week", "month" or "year". +# The first configuration item is the graph group, such as [day], [week], [month], [year] sections. +# The charts are defined under the graph group and can be renamed and reorganized. They will display on your website in the order they appear here. +# Under the chart are the observation names from the WeeWX database. Any item within your database "archive type" can be charted. For a list of "archive types" refer to this chart. http://weewx.com/docs/customizing.htm#archive_types +# Each observation can be customized with built-in Highcharts "series" options. Popular ones are color, name and zIndex. For a list of Highcharts Series options refer to https://api.highcharts.com/highcharts/series +# +# If a custom option broke your charts: +# Undo your change and run wee_reports. You do not need to restart weewx if you make a graphs.conf change. +# If that doesn't work, undo ALL changes and go back to the default graphs.conf.example configuration. +# There is no guarantee that every customization option will work. +# +# Detailed settings overview can be found in the wiki under Detailed Configuration Settings Overview +# +############################################################################### + +# Global Chart Defaults +# These are fallback options that charts will use if an option is not defined. +aggregate_type = None +time_length = day_ago_to_now +type = line +colors = "#7cb5ec, #b2df8a, #f7a35c, #8c6bb1, #dd3497, #e4d354, #268bd2, #f45b5b, #6a3d9a, #33a02c" +tooltip_date_format = "LLL" + +[homepage] + # Chart Timespan Defaults + title = "Home Page" + show_button = true + button_text = "Home Page" + time_length = day_ago_to_now + tooltip_date_format = "LLL" + gapsize = 300000 # This should be your archive_interval from weewx.conf multiplied by 1000 to get milliseconds. Standard is 5 minutes + + [[chart1]] + title = Temperature + [[[outTemp]]] + zIndex = 1 + name = Temperature + [[[dewpoint]]] + color = purple + + [[roseplt]] + title = Wind Rose + [[[windRose]]] + + [[windplt]] + # The combined Wind Chart works best in this configuration + title = Wind Speed and Direction + yaxis_min = 0 + [[[windDir]]] + zIndex = 2 + yAxis = 1 + yaxis_max = 360 + lineWidth = 0 + # This plot is to be shown on the Graphs Week page. So here we override the timespan default aggregate type to one specific to this chart + # aggregate_type = avg + [[[[marker]]]] + enabled = true + [[[[states]]]] + [[[[[hover]]]]] + lineWidthPlus = 0 + [[[windGust]]] + zIndex = 1 + [[[windSpeed]]] + type = area + + [[solarRadGraph]] + title = Solar Radiation and UV Index + [[[radiation]]] + name = Solar Radiation + zIndex = 1 + color = "#ffc83f" + threshold = 0 + [[[maxSolarRad]]] + name = Theoretical Max Solar Radiation + type = area + color = "#f7f2b4" + y_label = "W/m2" + threshold = 0 + + [[chart3]] + title = Rain + [[[rainRate]]] + yAxis = 1 + [[[rainTotal]]] + name = Rain Total + + [[chart4]] + title = Barometer + type = spline + [[[barometer]]] + color = "#BECC00" + yAxis_tickInterval = 0.01 + +[day] + # Chart Timespan Defaults + title = "Today" + show_button = true + button_text = "Day" + time_length = day_ago_to_now + tooltip_date_format = "LLL" + gapsize = 300000 # This should be your archive_interval from weewx.conf multiplied by 1000 to get milliseconds. Standard is 5 minutes + + [[chart1]] + title = Temperature + [[[outTemp]]] + zIndex = 1 + name = Temperature + [[[dewpoint]]] + color = purple + + [[roseplt]] + title = Wind Rose + [[[windRose]]] + + [[windplt]] + # The combined Wind Chart works best in this configuration + title = Wind Speed and Direction + yaxis_min = 0 + [[[windDir]]] + zIndex = 2 + yAxis = 1 + yaxis_max = 360 + lineWidth = 0 + # This plot is to be shown on the Graphs Week page. So here we override the timespan default aggregate type to one specific to this chart + # aggregate_type = avg + [[[[marker]]]] + enabled = true + [[[[states]]]] + [[[[[hover]]]]] + lineWidthPlus = 0 + [[[windGust]]] + zIndex = 1 + [[[windSpeed]]] + type = area + + [[haysChartDay]] + title = Wind Speed Today + [[[haysChart]]] + + + [[solarRadGraph]] + title = Solar Radiation and UV Index + [[[radiation]]] + name = Solar Radiation + zIndex = 1 + color = "#ffc83f" + [[[maxSolarRad]]] + name = Theoretical Max Solar Radiation + type = area + color = "#f7f2b4" + y_label = "W/m2" + + [[chart3]] + title = Rain + [[[rainRate]]] + yAxis = 1 + [[[rainTotal]]] + name = Rain Total + + [[chart4]] + title = Barometer + type = spline + [[[barometer]]] + color = "#BECC00" + yAxis_tickInterval = 0.01 + + [[inside]] + title = Inside + [[[inTemp]]] + zIndex = 1 + name = Temperature + [[[inDewpoint]]] + zIndex = 1 + name = Dewpoint + +[week] + # Chart Timespan Defaults + title = "This Week" + show_button = true + button_text = "Week" + time_length = week_ago_to_now # Last 7 days + tooltip_date_format = "LLLL" + aggregate_type = max + aggregate_interval = 3600 # 1 hour + gapsize = 3600000 # 1 hour in milliseconds + + [[chart1]] + title = Temperature + [[[outTemp]]] + zIndex = 1 + name = Temperature + [[[dewpoint]]] + color = purple + + [[roseplt]] + title = Wind Rose + [[[windRose]]] + + [[windplt]] + # The combined Wind Chart works best in this configuration + title = Wind Speed and Direction + yaxis_min = 0 + [[[windDir]]] + zIndex = 2 + yAxis = 1 + yaxis_max = 360 + lineWidth = 0 + # This plot is to be shown on the Graphs Week page. So here we override the timespan default aggregate type to one specific to this chart + aggregate_type = avg + [[[[marker]]]] + enabled = true + [[[[states]]]] + [[[[[hover]]]]] + lineWidthPlus = 0 + [[[windGust]]] + zIndex = 1 + [[[windSpeed]]] + type = area + + [[solarRadGraph]] + title = Solar Radiation and UV Index + [[[radiation]]] + name = Solar Radiation + zIndex = 1 + color = "#ffc83f" + [[[maxSolarRad]]] + name = Theoretical Max Solar Radiation + type = area + color = "#f7f2b4" + y_label = "W/m2" + + [[chart3]] + title = Rain + [[[rainRate]]] + yAxis = 1 + [[[rainTotal]]] + name = Rain Total + + [[chart4]] + title = Barometer + type = spline + [[[barometer]]] + color = "#BECC00" + yAxis_tickInterval = 0.01 + + [[inside]] + title = Inside + [[[inTemp]]] + zIndex = 1 + name = Temperature + [[[inDewpoint]]] + zIndex = 1 + name = Dewpoint + +[month] + # Chart Timespan Defaults + title = "This Month" + show_button = true + button_text = "Month" + type = spline + time_length = month_ago_to_now # Last 30 days + tooltip_date_format = "dddd LL" + aggregate_type = max + aggregate_interval = 86400 # 1 day + gapsize = 86400000 # 1 day in milliseconds + + [[chart1]] + title = Temperature + [[[outTemp]]] + zIndex = 1 + name = Temperature + [[[dewpoint]]] + color = purple + + [[roseplt]] + title = Wind Rose + [[[windRose]]] + + [[windplt]] + # The combined Wind Chart works best in this configuration + title = Wind Speed and Direction + yaxis_min = 0 + [[[windDir]]] + zIndex = 2 + yAxis = 1 + yaxis_max = 360 + lineWidth = 0 + # This plot is to be shown on the Graphs Week page. So here we override the timespan default aggregate type to one specific to this chart + aggregate_type = avg + [[[[marker]]]] + enabled = true + [[[[states]]]] + [[[[[hover]]]]] + lineWidthPlus = 0 + [[[windGust]]] + zIndex = 1 + [[[windSpeed]]] + type = area + + [[solarRadGraph]] + title = Solar Radiation and UV Index + [[[radiation]]] + name = Solar Radiation + zIndex = 1 + color = "#ffc83f" + [[[maxSolarRad]]] + name = Theoretical Max Solar Radiation + type = area + color = "#f7f2b4" + y_label = "W/m2" + + [[chart3]] + title = Rain + [[[rainRate]]] + yAxis = 1 + [[[rainTotal]]] + name = Rain Total + + [[chart4]] + title = Barometer + type = spline + [[[barometer]]] + color = "#BECC00" + yAxis_tickInterval = 0.01 + + [[inside]] + title = Inside + [[[inTemp]]] + zIndex = 1 + name = Temperature + [[[inDewpoint]]] + zIndex = 1 + name = Dewpoint + +[year] + # Chart Timespan Defaults + title = "This Year" + show_button = true + button_text = "Year" + type = spline + time_length = year_ago_to_now + tooltip_date_format = "dddd LL" + aggregate_type = max + aggregate_interval = 86400 # 1 day + gapsize = 86400000 # 1 day in milliseconds + + [[chart1]] + title = Temperature + [[[outTemp]]] + zIndex = 1 + name = Temperature + [[[dewpoint]]] + color = purple + + [[roseplt]] + title = Wind Rose + [[[windRose]]] + + [[windplt]] + # The combined Wind Chart works best in this configuration + title = Wind Speed and Direction + yaxis_min = 0 + [[[windDir]]] + zIndex = 2 + yAxis = 1 + yaxis_max = 360 + lineWidth = 0 + # This plot is to be shown on the Graphs Week page. So here we override the timespan default aggregate type to one specific to this chart + aggregate_type = avg + [[[[marker]]]] + enabled = true + [[[[states]]]] + [[[[[hover]]]]] + lineWidthPlus = 0 + [[[windGust]]] + zIndex = 1 + [[[windSpeed]]] + type = area + + [[solarRadGraph]] + title = Solar Radiation and UV Index + [[[radiation]]] + name = Solar Radiation + zIndex = 1 + color = "#ffc83f" + [[[maxSolarRad]]] + name = Theoretical Max Solar Radiation + type = area + color = "#f7f2b4" + y_label = "W/m2" + + [[chart3]] + title = Rain + [[[rainRate]]] + yAxis = 1 + [[[rainTotal]]] + name = Rain Total + + [[chart4]] + title = Barometer + type = spline + [[[barometer]]] + color = "#BECC00" + yAxis_tickInterval = 0.01 diff --git a/examples/mounts/skins/Highcharts_Belchertown/json/day.json.tmpl b/examples/mounts/skins/Highcharts_Belchertown/json/day.json.tmpl new file mode 100644 index 0000000..f88da8f --- /dev/null +++ b/examples/mounts/skins/Highcharts_Belchertown/json/day.json.tmpl @@ -0,0 +1,84 @@ +#errorCatcher Echo +[{ +"utcoffset": $utcOffset, +"temperatureplot": {"series": +{"outTemp": { "zIndex": "1", "name": "Temperature", "data": $outTempDayjson}, +"dewpoint": {"name": "Dew Point", "data": $dewpointDayjson}, +"appTemp": {"name": "Apparent Temperature", "data": $appTempDayjson}, +"inTemp": {"name": "Indoor Temperature", "data": $inTempDayjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"windchillplot": {"series": +{"windchill": {"name": "Wind Chill", "data": $windchillDayjson}, +"heatindex": {"name": "Heat Index", "data": $heatindexDayjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"humidityplot": {"series": +{"outHumidity": {"name": "Humidity", "data": $outHumidityDayjson}} +}, +"barometerplot": {"series": +{"barometer": {"name": "Barometer", "data": $barometerDayjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_pressure == "hPa" + "(hPa)" +#elif $unit.unit_type_dict.group_pressure == "inHg" + "(inHg)" +#elif $unit.unit_type_dict.group_pressure == "mmHg" + "(mmHg)" +#else + "(mbar)" +#end if +}}, +"windplot": {"series": +{"windSpeed": {"name": "Wind Speed", "data": $windSpeedDayjson}, +"windGust": {"name": "Wind Gust", "data": $windGustDayjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_speed == "km_per_hour" + "(km/h)" +#elif $unit.unit_type_dict.group_speed == "mile_per_hour" + "(mph)" +#elif $unit.unit_type_dict.group_speed == "meter_per_second" + "(m/s)" +#else + "(knot)" +#end if +}}, +"winddirplot": {"series": +{"windDir": {"name": "Wind Direction", "data": $windDirDayjson}} +}, +"rainplot": {"series": +{"rain": {"name": "Rain Rate", "data": $rainDayjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"rainplottotal": {"series": +{"rain": {"name": "Rainfall Total", "data": $rainDayTotaljson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"radiationplot": {"series": +{"radiation": {"name": "Solar Radiation", "data": $radiationDayjson}} +} +}] diff --git a/examples/mounts/skins/Highcharts_Belchertown/json/month.json.tmpl b/examples/mounts/skins/Highcharts_Belchertown/json/month.json.tmpl new file mode 100644 index 0000000..59612f2 --- /dev/null +++ b/examples/mounts/skins/Highcharts_Belchertown/json/month.json.tmpl @@ -0,0 +1,84 @@ +#errorCatcher Echo +[{ +"utcoffset": $utcOffset, +"temperatureplot": {"series": +{"outTemp": { "zIndex": "1", "name": "Max Temperature", "data": $outTempMonthjson}, +"outTempMin": {"name": "Min Temperature", "data": $outTempMinMonthjson}, +"dewpoint": {"name": "Dew Point", "data": $dewpointMonthjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"windchillplot": {"series": +{"windchill": {"name": "Wind Chill", "data": $windchillMonthjson}, +"heatindex": {"name": "Heat Index", "data": $heatindexMonthjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"humidityplot": {"series": +{"outHumidity": {"name": "Humidity", "data": $outHumidityMonthjson}} +}, +"barometerplot": {"series": +{"barometer": {"name": "Barometer", "data": $barometerMonthjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_pressure == "hPa" + "(hPa)" +#elif $unit.unit_type_dict.group_pressure == "inHg" + "(inHg)" +#elif $unit.unit_type_dict.group_pressure == "mmHg" + "(mmHg)" +#else + "(mbar)" +#end if +}}, +"windplot": {"series": +{"windSpeed": {"name": "Max Wind Speed", "data": $windSpeedMonthjson}, +"windSpeedAvg": {"name": "Average Wind Speed", "data": $windSpeedAvgMonthjson}, +"windGust": {"name": "Wind Gust", "data": $windGustMonthjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_speed == "km_per_hour" + "(km/h)" +#elif $unit.unit_type_dict.group_speed == "mile_per_hour" + "(mph)" +#elif $unit.unit_type_dict.group_speed == "meter_per_second" + "(m/s)" +#else + "(knot)" +#end if +}}, +"winddirplot": {"series": +{"windDir": {"name": "Wind Direction", "data": $windDirMonthjson}} +}, +"rainplot": {"series": +{"rain": {"name": "Rain Rate Max", "data": $rainMonthjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"rainplottotal": {"series": +{"rain": {"name": "Rainfall Total", "data": $rainMonthTotaljson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"radiationplot": {"series": +{"radiation": {"name": "Solar Radiation", "data": $radiationMonthjson}} +} +}] \ No newline at end of file diff --git a/examples/mounts/skins/Highcharts_Belchertown/json/week.json.tmpl b/examples/mounts/skins/Highcharts_Belchertown/json/week.json.tmpl new file mode 100644 index 0000000..761bc39 --- /dev/null +++ b/examples/mounts/skins/Highcharts_Belchertown/json/week.json.tmpl @@ -0,0 +1,84 @@ +#errorCatcher Echo +[{ +"utcoffset": $utcOffset, +"temperatureplot": {"series": +{"outTemp": {"zIndex": "1", "name": "Temperature", "data": $outTempWeekjson}, +"dewpoint": {"name": "Dew Point", "data": $dewpointWeekjson}, +"appTemp": {"name": "Apparent Temperature", "data": $appTempWeekjson}, +"inTemp": {"name": "Indoor Temperature", "data": $inTempWeekjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"windchillplot": {"series": +{"windchill": {"name": "Wind Chill", "data": $windchillWeekjson}, +"heatindex": {"name": "Heat Index", "data": $heatindexWeekjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"humidityplot": {"series": +{"outHumidity": {"name": "Humidity", "data": $outHumidityWeekjson}} +}, +"barometerplot": {"series": +{"barometer": {"name": "Barometer", "data": $barometerWeekjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_pressure == "hPa" + "(hPa)" +#elif $unit.unit_type_dict.group_pressure == "inHg" + "(inHg)" +#elif $unit.unit_type_dict.group_pressure == "mmHg" + "(mmHg)" +#else + "(mbar)" +#end if +}}, +"windplot": {"series": +{"windSpeed": {"name": "Wind Speed", "data": $windSpeedWeekjson}, +"windGust": {"name": "Wind Gust", "data": $windGustWeekjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_speed == "km_per_hour" + "(km/h)" +#elif $unit.unit_type_dict.group_speed == "mile_per_hour" + "(mph)" +#elif $unit.unit_type_dict.group_speed == "meter_per_second" + "(m/s)" +#else + "(knots)" +#end if +}}, +"winddirplot": {"series": +{"windDir": {"name": "Wind Direction", "data": $windDirWeekjson}} +}, +"rainplot": {"series": +{"rain": {"name": "Rain Rate Max", "data": $rainWeekjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"rainplottotal": {"series": +{"rain": {"name": "Rainfall Total", "data": $rainWeekTotaljson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"radiationplot": {"series": +{"radiation": {"name": "Solar Radiation", "data": $radiationWeekjson}} +} +}] \ No newline at end of file diff --git a/examples/mounts/skins/Highcharts_Belchertown/json/year.json.tmpl b/examples/mounts/skins/Highcharts_Belchertown/json/year.json.tmpl new file mode 100644 index 0000000..a70d731 --- /dev/null +++ b/examples/mounts/skins/Highcharts_Belchertown/json/year.json.tmpl @@ -0,0 +1,84 @@ +#errorCatcher Echo +[{ +"utcoffset": $utcOffset, +"temperatureplot": {"series": +{"outTemp": {"zIndex": "1", "name": "Max Temperature", "data": $outTempYearjson}, +"outTempMin": {"name": "Min Temperature", "data": $outTempMinYearjson}, +"dewpoint": {"name": "Dew Point", "data": $dewpointYearjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"windchillplot": {"series": +{"windchill": {"name": "Wind Chill", "data": $windchillYearjson}, +"heatindex": {"name": "Heat Index", "data": $heatindexYearjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_temperature == "degree_C" + "(\u00B0 C)" +#else + "(\u00B0 F)" +#end if +}}, +"humidityplot": {"series": +{"outHumidity": {"name": "Humidity", "data": $outHumidityYearjson}} +}, +"barometerplot": {"series": +{"barometer": {"name": "Barometer", "data": $barometerYearjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_pressure == "hPa" + "(hPa)" +#elif $unit.unit_type_dict.group_pressure == "inHg" + "(inHg)" +#elif $unit.unit_type_dict.group_pressure == "mmHg" + "(mmHg)" +#else + "(mbar)" +#end if +}}, +"windplot": {"series": +{"windSpeed": {"name": "Max Wind Speed", "data": $windSpeedYearjson}, +"windSpeedAvg": {"name": "Average Wind Speed", "data": $windSpeedAvgYearjson}, +"windGust": {"name": "Wind Gust", "data": $windGustYearjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_speed == "km_per_hour" + "(km/h)" +#elif $unit.unit_type_dict.group_speed == "mile_per_hour" + "(mph)" +#elif $unit.unit_type_dict.group_speed == "meter_per_second" + "(m/s)" +#else + "(knot)" +#end if +}}, +"winddirplot": {"series": +{"windDir": {"name": "Wind Direction", "data": $windDirYearjson}} +}, +"rainplot": {"series": +{"rain": {"name": "Rain Rate Max", "data": $rainYearjson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"rainplottotal": {"series": +{"rain": {"name": "Rainfall Total", "data": $rainYearTotaljson}}, +"yAxisLabel": {"text": #slurp +#if $unit.unit_type_dict.group_rain == "mm" + "(mm)" +#elif $unit.unit_type_dict.group_rain == "inch" + "(in)" +#else + "(cm)" +#end if +}}, +"radiationplot": {"series": +{"radiation": {"name": "Solar Radiation", "data": $radiationYearjson}} +} +}] \ No newline at end of file diff --git a/examples/mounts/skins/Highcharts_Belchertown/skin.conf b/examples/mounts/skins/Highcharts_Belchertown/skin.conf new file mode 100644 index 0000000..16871d9 --- /dev/null +++ b/examples/mounts/skins/Highcharts_Belchertown/skin.conf @@ -0,0 +1,231 @@ +############################################################################### +# SKIN CONFIGURATION FILE # +# Copyright (c) 2010 Tom Keffer # +############################################################################### + +[Extras] + +############################################################################### + +[Units] + # This section is for managing the selection and formatting of units. + + [[Groups]] + # For each group of measurements, this section sets what units to + # use for it. + # NB: The unit is always in the singular. I.e., 'mile_per_hour', + # NOT 'miles_per_hour' + + group_altitude = foot # Options are 'foot' or 'meter' + group_degree_day = degree_F_day # Options are 'degree_F_day' or 'degree_C_day' + group_direction = degree_compass + group_moisture = centibar + group_percent = percent + group_pressure = inHg # Options are 'inHg', 'mmHg', 'mbar', or 'hPa' + group_radiation = watt_per_meter_squared + group_rain = inch # Options are 'inch', 'cm', or 'mm' + group_rainrate = inch_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour' + group_speed = mile_per_hour # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second' + group_speed2 = mile_per_hour2 # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2' + group_temperature = degree_F # Options are 'degree_F' or 'degree_C' + group_uv = uv_index + group_volt = volt + + # The following are used internally and should not be changed: + group_count = count + group_interval = minute + group_time = unix_epoch + group_elapsed = second + + [[StringFormats]] + # This section sets the string formatting for each type of unit. + + centibar = %.0f + cm = %.2f + cm_per_hour = %.2f + degree_C = %.1f + degree_F = %.1f + degree_compass = %.0f + foot = %.0f + hPa = %.1f + hour = %.1f + inHg = %.3f + inch = %.2f + inch_per_hour = %.2f + km_per_hour = %.0f + km_per_hour2 = %.1f + knot = %.0f + knot2 = %.1f + mbar = %.1f + meter = %.0f + meter_per_second = %.1f + meter_per_second2 = %.1f + mile_per_hour = %.0f + mile_per_hour2 = %.1f + mm = %.1f + mmHg = %.1f + mm_per_hour = %.1f + percent = %.0f + second = %.0f + uv_index = %.1f + volt = %.1f + watt_per_meter_squared = %.0f + NONE = " N/A" + + [[Labels]] + # This section sets a label to be used for each type of unit. + + centibar = " cb" + cm = " cm" + cm_per_hour = " cm/hr" + degree_C = " °C" + degree_F = " °F" + degree_compass = ° + foot = " feet" + hPa = " hPa" + inHg = " inHg" + inch = " in" + inch_per_hour = " in/hr" + km_per_hour = " km/h" + km_per_hour2 = " km/h" + knot = " knots" + knot2 = " knots" + mbar = " mbar" + meter = " meters" + meter_per_second = " m/s" + meter_per_second2 = " m/s" + mile_per_hour = " mph" + mile_per_hour2 = " mph" + mm = " mm" + mmHg = " mmHg" + mm_per_hour = " mm/hr" + percent = % + volt = " V" + watt_per_meter_squared = " W/m²" + day = " day", " days" + hour = " hour", " hours" + minute = " minute", " minutes" + second = " second", " seconds" + NONE = "" + + [[TimeFormats]] + # This section sets the string format to be used for each time scale. + # The values below will work in every locale, but may not look + # particularly attractive. See the Customization Guide for alternatives. + + day = %X + week = %X (%A) + month = %x %X + year = %x %X + rainyear = %x %X + current = %x %X + ephem_day = %X + ephem_year = %x %X + + [[Ordinates]] + # The ordinal directions. The last one should be for no wind direction + directions = N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW, N/A + + [[DegreeDays]] + # This section sets the base temperatures used for the calculation + # of heating and cooling degree-days. + + # Base temperature for heating days, with unit: + heating_base = 65, degree_F + # Base temperature for cooling days, with unit: + cooling_base = 65, degree_F + + [[Trend]] + time_delta = 10800 # 3 hours + time_grace = 300 # 5 minutes + +############################################################################### + +[Labels] + # Labels used in this skin + + # Set to hemisphere abbreviations suitable for your location: + hemispheres = N, S, E, W + # Formats to be used for latitude whole degrees, longitude whole degrees, + # and minutes: + latlon_formats = "%02d", "%03d", "%05.2f" + + [[Generic]] + # Generic labels, keyed by an observation type. + + barometer = Barometer + dewpoint = Dew Point + heatindex = Heat Index + inHumidity = Inside Humidity + inTemp = Inside Temperature + outHumidity = Outside Humidity + outTemp = Outside Temperature + radiation = Radiation + rain = Rain + rainRate = Rain Rate + rxCheckPercent = ISS Signal Quality + UV = UV Index + windDir = Wind Direction + windGust = Gust Speed + windGustDir = Gust Direction + windSpeed = Wind Speed + windchill = Wind Chill + windgustvec = Gust Vector + windvec = Wind Vector + +############################################################################### + +[Almanac] + # The labels to be used for the phases of the moon: + moon_phases = New Moon, Waxing Crescent, First Quarter, Waxing Gibbous, Full Moon, Waning Gibbous, Last Quarter, Waning Crescent + +############################################################################### + +[CheetahGenerator] + # This section is used by the generator CheetahGenerator, and specifies + # which files are to be generated from which template. + + search_list_extensions = user.belchertown_highchartsSearchX.highchartsDay, user.belchertown_highchartsSearchX.highchartsWeek, user.belchertown_highchartsSearchX.highchartsMonth, user.belchertown_highchartsSearchX.highchartsYear + + # Possible encodings are 'html_entities', 'utf8', or 'strict_ascii' + encoding = html_entities + + [[ToDate]] + # Highcharts day json data + [[[DayJSON]]] + template = json/day.json.tmpl + + # Highcharts week json data + [[[WeekJSON]]] + template = json/week.json.tmpl + + # Highcharts month json data + [[[MonthJSON]]] + template = json/month.json.tmpl + + # Highcharts year json data + [[[YearJSON]]] + template = json/year.json.tmpl + +############################################################################### + +[CopyGenerator] + + # This section is used by the generator CopyGenerator + + # List of files to be copied only the first time the generator runs + copy_once = + + # List of files to be copied each time the generator runs + copy_always = + + +############################################################################### + +# +# The list of generators that are to be run: +# +[Generators] + generator_list = weewx.cheetahgenerator.CheetahGenerator, weewx.reportengine.CopyGenerator + + diff --git a/extensions/weewx-mqtt.zip b/extensions/weewx-mqtt.zip new file mode 100644 index 0000000000000000000000000000000000000000..d57408c309ce12f0bbccf9a800c1232a3e7b80c2 GIT binary patch literal 8256 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 e<>KUG=H%oy0&#M(G8?cOF`F2$gV