Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de19de2129 | ||
|
|
1719263de0 | ||
|
|
e70b872c98 | ||
|
|
b7d28238ab | ||
|
|
6c9a8b0692 | ||
|
|
9f3dba3aab | ||
|
|
e4e4ad4107 | ||
|
|
e8fb9570bb | ||
|
|
bc42099962 | ||
|
|
be71cbe609 | ||
|
|
0d6df03c94 | ||
|
|
d777040c0a | ||
|
|
a5636a60f8 | ||
|
|
6f817b2ed5 | ||
|
|
e4fec4f4c2 | ||
|
|
3a25964ec4 | ||
|
|
1227dff412 | ||
|
|
26ee2e6efc | ||
|
|
d6a8d31278 | ||
|
|
3f2b534baa | ||
|
|
70f413013c | ||
|
|
6edcd174bb | ||
|
|
3170ef6ce9 | ||
|
|
fb56f4d012 | ||
|
|
c5756f0cba | ||
|
|
95c9ecc8b2 | ||
|
|
bdee066c33 | ||
|
|
957039d0c0 | ||
|
|
dd23a0fa60 | ||
|
|
7777a0a059 | ||
|
|
e8fc6d48bf | ||
|
|
c98148c886 | ||
|
|
6ba2b4060e | ||
|
|
762c17ca8e | ||
|
|
4b15ac74fc |
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
||||
custom: ["https://paypal.me/gskjold"]
|
||||
custom: ["https://amsleser.no"]
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Meter configuration
|
||||
url: https://github.com/gskjold/AmsToMqttBridge/wiki/Known-hardware-configurations
|
||||
url: https://github.com/UtilitechAS/amsreader-firmware/wiki/Known-hardware-configurations
|
||||
about: Please check your meter configuration here first.
|
||||
- name: Frequently asked questions
|
||||
url: https://github.com/gskjold/AmsToMqttBridge/wiki/FAQ
|
||||
url: https://github.com/UtilitechAS/amsreader-firmware/wiki/FAQ
|
||||
about: Please check frequently asked questions first.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# AMS MQTT Bridge
|
||||
# AMS Reader
|
||||
This code is designed to decode data from electric smart meters installed in many countries in Europe these days. The data is presented in a graphical web interface and can also send the data to a MQTT broker which makes it suitable for home automation project. Originally it was only designed to work with Norwegian meters, but has since been adapter to read any IEC-62056-7-5 or IEC-62056-21 compliant meters.
|
||||
|
||||
Later development have added Energy usage graph for both day and month, as well as future energy price (Prices only available for ESP32). The code can run on any ESP8266 or ESP32 hardware which you can read more about in the [WiKi](https://github.com/gskjold/AmsToMqttBridge/wiki). If you don't have the knowledge to set up a ESP device yourself, have a look at the shop at [amsleser.no](https://amsleser.no/).
|
||||
Later development have added Energy usage graph for both day and month, as well as future energy price. The code can run on any ESP8266 or ESP32 hardware which you can read more about in the [WiKi](https://github.com/UtilitechAS/amsreader-firmware/wiki). If you don't have the knowledge to set up a ESP device yourself, have a look at the shop at [amsleser.no](https://amsleser.no/).
|
||||
|
||||
|
||||
<img src="webui.png">
|
||||
<img src="images/dashboard.png">
|
||||
|
||||
Go to the [WiKi](https://github.com/gskjold/AmsToMqttBridge/wiki) for information on how to get your own device! And find the latest prebuilt firmware file at the [release section](https://github.com/gskjold/AmsToMqttBridge/releases).
|
||||
Go to the [WiKi](https://github.com/UtilitechAS/amsreader-firmware/wiki) for information on how to get your own device! And find the latest prebuilt firmware file at the [release section](https://github.com/UtilitechAS/amsreader-firmware/releases).
|
||||
|
||||
## Building this project with PlatformIO
|
||||
To build this project, you need [PlatformIO](https://platformio.org/) installed.
|
||||
|
||||
@@ -1 +1 @@
|
||||
[See Hardware page in Wiki](https://github.com/gskjold/AmsToMqttBridge/wiki)
|
||||
[See Hardware page in Wiki](https://github.com/UtilitechAS/amsreader-firmware/wiki)
|
||||
|
||||
76
hardware/v1/kicad/HAN_ESP_TSS721.kicad_prl
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 0,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": true,
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.6
|
||||
},
|
||||
"ratsnest_display_mode": 0,
|
||||
"selection_filter": {
|
||||
"dimensions": true,
|
||||
"footprints": true,
|
||||
"graphics": true,
|
||||
"keepouts": true,
|
||||
"lockedItems": true,
|
||||
"otherItems": true,
|
||||
"pads": true,
|
||||
"text": true,
|
||||
"tracks": true,
|
||||
"vias": true,
|
||||
"zones": true
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36
|
||||
],
|
||||
"visible_layers": "fffffff_ffffffff",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"meta": {
|
||||
"filename": "HAN_ESP_TSS721.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
||||
440
hardware/v1/kicad/HAN_ESP_TSS721.kicad_pro
Normal file
@@ -0,0 +1,440 @@
|
||||
{
|
||||
"board": {
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"board_outline_line_width": 0.15,
|
||||
"copper_line_width": 0.19999999999999998,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.3,
|
||||
"copper_text_upright": false,
|
||||
"courtyard_line_width": 0.049999999999999996,
|
||||
"dimension_precision": 4,
|
||||
"dimension_units": 3,
|
||||
"dimensions": {
|
||||
"arrow_length": 1270000,
|
||||
"extension_offset": 500000,
|
||||
"keep_text_aligned": true,
|
||||
"suppress_zeroes": false,
|
||||
"text_position": 0,
|
||||
"units_format": 1
|
||||
},
|
||||
"fab_line_width": 0.09999999999999999,
|
||||
"fab_text_italic": false,
|
||||
"fab_text_size_h": 1.0,
|
||||
"fab_text_size_v": 1.0,
|
||||
"fab_text_thickness": 0.15,
|
||||
"fab_text_upright": false,
|
||||
"other_line_width": 0.09999999999999999,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 0.762,
|
||||
"height": 1.524,
|
||||
"width": 1.524
|
||||
},
|
||||
"silk_line_width": 0.15,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.0,
|
||||
"silk_text_size_v": 1.0,
|
||||
"silk_text_thickness": 0.15,
|
||||
"silk_text_upright": false,
|
||||
"zones": {
|
||||
"45_degree_only": true,
|
||||
"min_clearance": 0.508
|
||||
}
|
||||
},
|
||||
"diff_pair_dimensions": [],
|
||||
"drc_exclusions": [],
|
||||
"meta": {
|
||||
"filename": "board_design_settings.json",
|
||||
"version": 2
|
||||
},
|
||||
"rule_severities": {
|
||||
"annular_width": "error",
|
||||
"clearance": "error",
|
||||
"copper_edge_clearance": "error",
|
||||
"courtyards_overlap": "error",
|
||||
"diff_pair_gap_out_of_range": "error",
|
||||
"diff_pair_uncoupled_length_too_long": "error",
|
||||
"drill_out_of_range": "error",
|
||||
"duplicate_footprints": "warning",
|
||||
"extra_footprint": "warning",
|
||||
"footprint_type_mismatch": "error",
|
||||
"hole_clearance": "error",
|
||||
"hole_near_hole": "error",
|
||||
"invalid_outline": "error",
|
||||
"item_on_disabled_layer": "error",
|
||||
"items_not_allowed": "error",
|
||||
"length_out_of_range": "error",
|
||||
"malformed_courtyard": "error",
|
||||
"microvia_drill_out_of_range": "error",
|
||||
"missing_courtyard": "ignore",
|
||||
"missing_footprint": "warning",
|
||||
"net_conflict": "warning",
|
||||
"npth_inside_courtyard": "ignore",
|
||||
"padstack": "error",
|
||||
"pth_inside_courtyard": "ignore",
|
||||
"shorting_items": "error",
|
||||
"silk_over_copper": "warning",
|
||||
"silk_overlap": "warning",
|
||||
"skew_out_of_range": "error",
|
||||
"through_hole_pad_without_hole": "error",
|
||||
"too_many_vias": "error",
|
||||
"track_dangling": "warning",
|
||||
"track_width": "error",
|
||||
"tracks_crossing": "error",
|
||||
"unconnected_items": "error",
|
||||
"unresolved_variable": "error",
|
||||
"via_dangling": "warning",
|
||||
"zone_has_empty_net": "error",
|
||||
"zones_intersect": "error"
|
||||
},
|
||||
"rules": {
|
||||
"allow_blind_buried_vias": false,
|
||||
"allow_microvias": false,
|
||||
"max_error": 0.005,
|
||||
"min_clearance": 0.0,
|
||||
"min_copper_edge_clearance": 0.075,
|
||||
"min_hole_clearance": 0.25,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.19999999999999998,
|
||||
"min_microvia_drill": 0.09999999999999999,
|
||||
"min_silk_clearance": 0.0,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.19999999999999998,
|
||||
"min_via_annular_width": 0.049999999999999996,
|
||||
"min_via_diameter": 0.39999999999999997,
|
||||
"use_height_for_length_calcs": true
|
||||
},
|
||||
"track_widths": [
|
||||
0.0,
|
||||
0.2,
|
||||
0.4,
|
||||
0.6,
|
||||
1.0
|
||||
],
|
||||
"via_dimensions": [],
|
||||
"zones_allow_external_fillets": false,
|
||||
"zones_use_no_outline": true
|
||||
},
|
||||
"layer_presets": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"erc": {
|
||||
"erc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"pin_map": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
]
|
||||
],
|
||||
"rule_severities": {
|
||||
"bus_definition_conflict": "error",
|
||||
"bus_entry_needed": "error",
|
||||
"bus_label_syntax": "error",
|
||||
"bus_to_bus_conflict": "error",
|
||||
"bus_to_net_conflict": "error",
|
||||
"different_unit_footprint": "error",
|
||||
"different_unit_net": "error",
|
||||
"duplicate_reference": "error",
|
||||
"duplicate_sheet_names": "error",
|
||||
"extra_units": "error",
|
||||
"global_label_dangling": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"label_dangling": "error",
|
||||
"lib_symbol_issues": "warning",
|
||||
"multiple_net_names": "warning",
|
||||
"net_not_bus_member": "warning",
|
||||
"no_connect_connected": "warning",
|
||||
"no_connect_dangling": "warning",
|
||||
"pin_not_connected": "error",
|
||||
"pin_not_driven": "error",
|
||||
"pin_to_pin": "warning",
|
||||
"power_pin_not_driven": "error",
|
||||
"similar_labels": "warning",
|
||||
"unannotated": "error",
|
||||
"unit_value_mismatch": "error",
|
||||
"unresolved_variable": "error",
|
||||
"wire_dangling": "error"
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "HAN_ESP_TSS721.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.2,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.25,
|
||||
"via_diameter": 0.6,
|
||||
"via_drill": 0.4,
|
||||
"wire_width": 6.0
|
||||
},
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.5,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.5,
|
||||
"microvia_drill": 0.2,
|
||||
"name": "PWR",
|
||||
"nets": [
|
||||
"+3V3"
|
||||
],
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.5,
|
||||
"via_diameter": 0.8,
|
||||
"via_drill": 0.6,
|
||||
"wire_width": 6.0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"net_colors": null
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"annotate_start_num": 0,
|
||||
"drawing": {
|
||||
"default_line_thickness": 6.0,
|
||||
"default_text_size": 50.0,
|
||||
"field_names": [],
|
||||
"intersheets_ref_own_page": false,
|
||||
"intersheets_ref_prefix": "",
|
||||
"intersheets_ref_short": false,
|
||||
"intersheets_ref_show": false,
|
||||
"intersheets_ref_suffix": "",
|
||||
"junction_size_choice": 3,
|
||||
"label_size_ratio": 0.25,
|
||||
"pin_symbol_size": 0.0,
|
||||
"text_offset_ratio": 0.08
|
||||
},
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": [],
|
||||
"meta": {
|
||||
"version": 1
|
||||
},
|
||||
"net_format_name": "",
|
||||
"ngspice": {
|
||||
"fix_include_paths": true,
|
||||
"fix_passive_vals": false,
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"model_mode": 0,
|
||||
"workbook_filename": ""
|
||||
},
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"spice_adjust_passive_values": false,
|
||||
"spice_external_command": "spice \"%I\"",
|
||||
"subpart_first_id": 65,
|
||||
"subpart_id_separator": 0
|
||||
},
|
||||
"sheets": [],
|
||||
"text_variables": {}
|
||||
}
|
||||
1
hardware/v1/kicad/fp-info-cache
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,3 @@
|
||||
EESchema-DOCLIB Version 2.0
|
||||
#
|
||||
#End Doc Library
|
||||
@@ -1,6 +1,21 @@
|
||||
EESchema-LIBRARY Version 2.4
|
||||
#encoding utf-8
|
||||
#
|
||||
# +3.3V-power
|
||||
#
|
||||
DEF +3.3V-power #PWR 0 0 Y Y 1 F P
|
||||
F0 "#PWR" 0 -150 50 H I C CNN
|
||||
F1 "+3.3V-power" 0 140 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
DRAW
|
||||
P 2 0 1 0 -30 50 0 100 N
|
||||
P 2 0 1 0 0 0 0 100 N
|
||||
P 2 0 1 0 0 100 30 50 N
|
||||
X +3V3 1 0 0 0 U 50 50 1 1 W N
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# CONN_01X08
|
||||
#
|
||||
DEF CONN_01X08 P 0 40 Y N 1 F N
|
||||
@@ -35,4 +50,23 @@ X P8 8 -200 -350 150 R 50 50 1 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
# Jumper-Device
|
||||
#
|
||||
DEF Jumper-Device JP 0 30 Y N 1 F N
|
||||
F0 "JP" 0 150 50 H V C CNN
|
||||
F1 "Jumper-Device" 0 -80 50 H V C CNN
|
||||
F2 "" 0 0 50 H I C CNN
|
||||
F3 "" 0 0 50 H I C CNN
|
||||
$FPLIST
|
||||
SolderJumper*
|
||||
$ENDFPLIST
|
||||
DRAW
|
||||
C -100 0 35 0 1 0 N
|
||||
A 0 -26 125 375 1422 0 1 0 N 99 50 -98 50
|
||||
C 100 0 35 0 1 0 N
|
||||
X 1 1 -300 0 165 R 50 50 0 1 P
|
||||
X 2 2 300 0 165 L 50 50 0 1 P
|
||||
ENDDRAW
|
||||
ENDDEF
|
||||
#
|
||||
#End Library
|
||||
|
||||
75
hardware/wemos_mbus_shield/kicad/d1_mini_shield.kicad_prl
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"board": {
|
||||
"active_layer": 0,
|
||||
"active_layer_preset": "",
|
||||
"auto_track_width": true,
|
||||
"hidden_nets": [],
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"pads": 1.0,
|
||||
"tracks": 1.0,
|
||||
"vias": 1.0,
|
||||
"zones": 0.6
|
||||
},
|
||||
"ratsnest_display_mode": 0,
|
||||
"selection_filter": {
|
||||
"dimensions": true,
|
||||
"footprints": true,
|
||||
"graphics": true,
|
||||
"keepouts": true,
|
||||
"lockedItems": true,
|
||||
"otherItems": true,
|
||||
"pads": true,
|
||||
"text": true,
|
||||
"tracks": true,
|
||||
"vias": true,
|
||||
"zones": true
|
||||
},
|
||||
"visible_items": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
13,
|
||||
14,
|
||||
15,
|
||||
16,
|
||||
17,
|
||||
18,
|
||||
19,
|
||||
20,
|
||||
21,
|
||||
22,
|
||||
23,
|
||||
24,
|
||||
25,
|
||||
26,
|
||||
27,
|
||||
28,
|
||||
29,
|
||||
30,
|
||||
32,
|
||||
33,
|
||||
34,
|
||||
35,
|
||||
36
|
||||
],
|
||||
"visible_layers": "fffffff_ffffffff",
|
||||
"zone_display_mode": 0
|
||||
},
|
||||
"meta": {
|
||||
"filename": "d1_mini_shield.kicad_prl",
|
||||
"version": 3
|
||||
},
|
||||
"project": {
|
||||
"files": []
|
||||
}
|
||||
}
|
||||
356
hardware/wemos_mbus_shield/kicad/d1_mini_shield.kicad_pro
Normal file
@@ -0,0 +1,356 @@
|
||||
{
|
||||
"board": {
|
||||
"design_settings": {
|
||||
"defaults": {
|
||||
"board_outline_line_width": 0.15,
|
||||
"copper_line_width": 0.2,
|
||||
"copper_text_italic": false,
|
||||
"copper_text_size_h": 1.5,
|
||||
"copper_text_size_v": 1.5,
|
||||
"copper_text_thickness": 0.3,
|
||||
"copper_text_upright": true,
|
||||
"courtyard_line_width": 0.05,
|
||||
"other_line_width": 0.15,
|
||||
"other_text_italic": false,
|
||||
"other_text_size_h": 1.0,
|
||||
"other_text_size_v": 1.0,
|
||||
"other_text_thickness": 0.15,
|
||||
"other_text_upright": true,
|
||||
"silk_line_width": 0.15,
|
||||
"silk_text_italic": false,
|
||||
"silk_text_size_h": 1.0,
|
||||
"silk_text_size_v": 1.0,
|
||||
"silk_text_thickness": 0.15,
|
||||
"silk_text_upright": true
|
||||
},
|
||||
"diff_pair_dimensions": [
|
||||
{
|
||||
"gap": 0.25,
|
||||
"via_gap": 0.25,
|
||||
"width": 0.2
|
||||
}
|
||||
],
|
||||
"drc_exclusions": [],
|
||||
"rule_severitieslegacy_courtyards_overlap": true,
|
||||
"rule_severitieslegacy_no_courtyard_defined": false,
|
||||
"rules": {
|
||||
"allow_blind_buried_vias": false,
|
||||
"allow_microvias": false,
|
||||
"min_hole_to_hole": 0.25,
|
||||
"min_microvia_diameter": 0.2,
|
||||
"min_microvia_drill": 0.09999999999999999,
|
||||
"min_through_hole_diameter": 0.3,
|
||||
"min_track_width": 0.2,
|
||||
"min_via_diameter": 0.4,
|
||||
"solder_mask_clearance": 0.2,
|
||||
"solder_mask_min_width": 0.0,
|
||||
"solder_paste_clearance": 0.0,
|
||||
"solder_paste_margin_ratio": -0.0
|
||||
},
|
||||
"track_widths": [
|
||||
0.25,
|
||||
0.5
|
||||
],
|
||||
"via_dimensions": [
|
||||
{
|
||||
"diameter": 0.6,
|
||||
"drill": 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
"layer_presets": []
|
||||
},
|
||||
"boards": [],
|
||||
"cvpcb": {
|
||||
"equivalence_files": []
|
||||
},
|
||||
"erc": {
|
||||
"erc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"pin_map": [
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
0,
|
||||
0,
|
||||
2
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2,
|
||||
2
|
||||
]
|
||||
],
|
||||
"rule_severities": {
|
||||
"bus_definition_conflict": "error",
|
||||
"bus_entry_needed": "error",
|
||||
"bus_label_syntax": "error",
|
||||
"bus_to_bus_conflict": "error",
|
||||
"bus_to_net_conflict": "error",
|
||||
"different_unit_footprint": "error",
|
||||
"different_unit_net": "error",
|
||||
"duplicate_reference": "error",
|
||||
"duplicate_sheet_names": "error",
|
||||
"extra_units": "error",
|
||||
"global_label_dangling": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"label_dangling": "error",
|
||||
"lib_symbol_issues": "warning",
|
||||
"multiple_net_names": "warning",
|
||||
"net_not_bus_member": "warning",
|
||||
"no_connect_connected": "warning",
|
||||
"no_connect_dangling": "warning",
|
||||
"pin_not_connected": "error",
|
||||
"pin_not_driven": "error",
|
||||
"pin_to_pin": "warning",
|
||||
"power_pin_not_driven": "error",
|
||||
"similar_labels": "warning",
|
||||
"unannotated": "error",
|
||||
"unit_value_mismatch": "error",
|
||||
"unresolved_variable": "error",
|
||||
"wire_dangling": "error"
|
||||
}
|
||||
},
|
||||
"libraries": {
|
||||
"pinned_footprint_libs": [],
|
||||
"pinned_symbol_libs": []
|
||||
},
|
||||
"meta": {
|
||||
"filename": "d1_mini_shield.kicad_pro",
|
||||
"version": 1
|
||||
},
|
||||
"net_settings": {
|
||||
"classes": [
|
||||
{
|
||||
"bus_width": 12.0,
|
||||
"clearance": 0.2,
|
||||
"diff_pair_gap": 0.25,
|
||||
"diff_pair_via_gap": 0.25,
|
||||
"diff_pair_width": 0.2,
|
||||
"line_style": 0,
|
||||
"microvia_diameter": 0.3,
|
||||
"microvia_drill": 0.1,
|
||||
"name": "Default",
|
||||
"pcb_color": "rgba(0, 0, 0, 0.000)",
|
||||
"schematic_color": "rgba(0, 0, 0, 0.000)",
|
||||
"track_width": 0.25,
|
||||
"via_diameter": 0.8,
|
||||
"via_drill": 0.4,
|
||||
"wire_width": 6.0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"version": 2
|
||||
},
|
||||
"net_colors": null
|
||||
},
|
||||
"pcbnew": {
|
||||
"last_paths": {
|
||||
"gencad": "",
|
||||
"idf": "",
|
||||
"netlist": "d1_mini_shield.net",
|
||||
"specctra_dsn": "",
|
||||
"step": "",
|
||||
"vrml": ""
|
||||
},
|
||||
"page_layout_descr_file": ""
|
||||
},
|
||||
"schematic": {
|
||||
"annotate_start_num": 0,
|
||||
"drawing": {
|
||||
"default_line_thickness": 6.0,
|
||||
"default_text_size": 50.0,
|
||||
"field_names": [],
|
||||
"intersheets_ref_own_page": false,
|
||||
"intersheets_ref_prefix": "",
|
||||
"intersheets_ref_short": false,
|
||||
"intersheets_ref_show": false,
|
||||
"intersheets_ref_suffix": "",
|
||||
"junction_size_choice": 3,
|
||||
"label_size_ratio": 0.25,
|
||||
"pin_symbol_size": 0.0,
|
||||
"text_offset_ratio": 0.08
|
||||
},
|
||||
"legacy_lib_dir": "",
|
||||
"legacy_lib_list": [],
|
||||
"meta": {
|
||||
"version": 1
|
||||
},
|
||||
"net_format_name": "Pcbnew",
|
||||
"ngspice": {
|
||||
"fix_include_paths": true,
|
||||
"fix_passive_vals": false,
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"model_mode": 0,
|
||||
"workbook_filename": ""
|
||||
},
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"spice_adjust_passive_values": false,
|
||||
"spice_external_command": "spice \"%I\"",
|
||||
"subpart_first_id": 65,
|
||||
"subpart_id_separator": 0
|
||||
},
|
||||
"sheets": [],
|
||||
"text_variables": {}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 173 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 32 KiB |
@@ -22,10 +22,6 @@
|
||||
#define CONFIG_NTP_START 872
|
||||
#define CONFIG_MQTT_START 1004
|
||||
|
||||
#define CONFIG_MQTT_START_86 224
|
||||
#define CONFIG_METER_START_87 784
|
||||
#define CONFIG_ENTSOE_START_90 286
|
||||
#define CONFIG_WIFI_START_91 16
|
||||
#define CONFIG_METER_START_93 224
|
||||
|
||||
|
||||
@@ -34,20 +30,8 @@ struct SystemConfig {
|
||||
bool vendorConfigured;
|
||||
bool userConfigured;
|
||||
uint8_t dataCollectionConsent; // 0 = unknown, 1 = accepted, 2 = declined
|
||||
char country[2];
|
||||
}; // 6
|
||||
|
||||
struct WiFiConfig91 {
|
||||
char ssid[32];
|
||||
char psk[64];
|
||||
char ip[15];
|
||||
char gateway[15];
|
||||
char subnet[15];
|
||||
char dns1[15];
|
||||
char dns2[15];
|
||||
char hostname[32];
|
||||
bool mdns;
|
||||
}; // 204
|
||||
char country[3];
|
||||
}; // 7
|
||||
|
||||
struct WiFiConfig {
|
||||
char ssid[32];
|
||||
@@ -65,18 +49,6 @@ struct WiFiConfig {
|
||||
bool autoreboot;
|
||||
}; // 213
|
||||
|
||||
struct MqttConfig86 {
|
||||
char host[128];
|
||||
uint16_t port;
|
||||
char clientId[32];
|
||||
char publishTopic[64];
|
||||
char subscribeTopic[64];
|
||||
char username[64];
|
||||
char password[64];
|
||||
uint8_t payloadFormat;
|
||||
bool ssl;
|
||||
}; // 420
|
||||
|
||||
struct MqttConfig {
|
||||
char host[128];
|
||||
uint16_t port;
|
||||
@@ -110,7 +82,7 @@ struct MeterConfig {
|
||||
uint32_t accumulatedMultiplier;
|
||||
uint8_t source;
|
||||
uint8_t parser;
|
||||
}; // 52
|
||||
}; // 61
|
||||
|
||||
struct MeterConfig100 {
|
||||
uint32_t baud;
|
||||
@@ -127,7 +99,7 @@ struct MeterConfig100 {
|
||||
uint32_t accumulatedMultiplier;
|
||||
uint8_t source;
|
||||
uint8_t parser;
|
||||
}; // 50
|
||||
}; // 59
|
||||
|
||||
struct MeterConfig95 {
|
||||
uint32_t baud;
|
||||
@@ -146,16 +118,6 @@ struct MeterConfig95 {
|
||||
uint8_t parser;
|
||||
}; // 50
|
||||
|
||||
struct MeterConfig87 {
|
||||
uint8_t type;
|
||||
uint8_t distributionSystem;
|
||||
uint8_t mainFuse;
|
||||
uint8_t productionCapacity;
|
||||
uint8_t encryptionKey[16];
|
||||
uint8_t authenticationKey[16];
|
||||
bool substituteMissing;
|
||||
}; // 37
|
||||
|
||||
struct DebugConfig {
|
||||
bool telnet;
|
||||
bool serial;
|
||||
@@ -331,9 +293,6 @@ private:
|
||||
uint8_t tempSensorCount = 0;
|
||||
TempSensorConfig** tempSensors = NULL;
|
||||
|
||||
bool relocateConfig90(); // 2.0.0
|
||||
bool relocateConfig91(); // 2.0.2
|
||||
bool relocateConfig92(); // 2.0.3
|
||||
bool relocateConfig93(); // 2.1.0
|
||||
bool relocateConfig94(); // 2.1.0
|
||||
bool relocateConfig95(); // 2.1.4
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
String toHex(uint8_t* in);
|
||||
String toHex(uint8_t* in, uint16_t size);
|
||||
void fromHex(uint8_t *out, String in, uint16_t size);
|
||||
void stripNonAscii(uint8_t* in, uint16_t size);
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "AmsConfiguration.h"
|
||||
#include "hexutils.h"
|
||||
|
||||
bool AmsConfiguration::getSystemConfig(SystemConfig& config) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@@ -19,6 +20,7 @@ bool AmsConfiguration::getSystemConfig(SystemConfig& config) {
|
||||
|
||||
bool AmsConfiguration::setSystemConfig(SystemConfig& config) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
stripNonAscii((uint8_t*) config.country, 2);
|
||||
EEPROM.put(CONFIG_SYSTEM_START, config);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
@@ -59,6 +61,16 @@ bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) {
|
||||
} else {
|
||||
wifiChanged = true;
|
||||
}
|
||||
|
||||
stripNonAscii((uint8_t*) config.ssid, 32);
|
||||
stripNonAscii((uint8_t*) config.psk, 64);
|
||||
stripNonAscii((uint8_t*) config.ip, 16);
|
||||
stripNonAscii((uint8_t*) config.gateway, 16);
|
||||
stripNonAscii((uint8_t*) config.subnet, 16);
|
||||
stripNonAscii((uint8_t*) config.dns1, 16);
|
||||
stripNonAscii((uint8_t*) config.dns2, 16);
|
||||
stripNonAscii((uint8_t*) config.hostname, 32);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_WIFI_START, config);
|
||||
bool ret = EEPROM.commit();
|
||||
@@ -127,6 +139,14 @@ bool AmsConfiguration::setMqttConfig(MqttConfig& config) {
|
||||
} else {
|
||||
mqttChanged = true;
|
||||
}
|
||||
|
||||
stripNonAscii((uint8_t*) config.host, 128);
|
||||
stripNonAscii((uint8_t*) config.clientId, 32);
|
||||
stripNonAscii((uint8_t*) config.publishTopic, 64);
|
||||
stripNonAscii((uint8_t*) config.subscribeTopic, 64);
|
||||
stripNonAscii((uint8_t*) config.username, 128);
|
||||
stripNonAscii((uint8_t*) config.password, 256);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_MQTT_START, config);
|
||||
bool ret = EEPROM.commit();
|
||||
@@ -171,6 +191,10 @@ bool AmsConfiguration::getWebConfig(WebConfig& config) {
|
||||
}
|
||||
|
||||
bool AmsConfiguration::setWebConfig(WebConfig& config) {
|
||||
|
||||
stripNonAscii((uint8_t*) config.username, 64);
|
||||
stripNonAscii((uint8_t*) config.password, 64);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_WEB_START, config);
|
||||
bool ret = EEPROM.commit();
|
||||
@@ -221,8 +245,8 @@ void AmsConfiguration::clearMeter(MeterConfig& config) {
|
||||
config.baud = 0;
|
||||
config.parity = 0;
|
||||
config.invert = false;
|
||||
config.distributionSystem = 0;
|
||||
config.mainFuse = 0;
|
||||
config.distributionSystem = 2;
|
||||
config.mainFuse = 40;
|
||||
config.productionCapacity = 0;
|
||||
memset(config.encryptionKey, 0, 16);
|
||||
memset(config.authenticationKey, 0, 16);
|
||||
@@ -334,8 +358,9 @@ bool AmsConfiguration::pinUsed(uint8_t pin, GpioConfig& config) {
|
||||
}
|
||||
|
||||
bool AmsConfiguration::getGpioConfig(GpioConfig& config) {
|
||||
if(hasConfig()) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
uint8_t configVersion = EEPROM.read(EEPROM_CONFIG_ADDRESS);
|
||||
if(configVersion == EEPROM_CHECK_SUM || configVersion == EEPROM_CLEARED_INDICATOR) {
|
||||
EEPROM.get(CONFIG_GPIO_START, config);
|
||||
EEPROM.end();
|
||||
return true;
|
||||
@@ -445,6 +470,10 @@ bool AmsConfiguration::setNtpConfig(NtpConfig& config) {
|
||||
} else {
|
||||
ntpChanged = true;
|
||||
}
|
||||
|
||||
stripNonAscii((uint8_t*) config.server, 64);
|
||||
stripNonAscii((uint8_t*) config.timezone, 32);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_NTP_START, config);
|
||||
bool ret = EEPROM.commit();
|
||||
@@ -477,6 +506,7 @@ bool AmsConfiguration::getEntsoeConfig(EntsoeConfig& config) {
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
clearEntsoe(config);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -492,6 +522,11 @@ bool AmsConfiguration::setEntsoeConfig(EntsoeConfig& config) {
|
||||
} else {
|
||||
entsoeChanged = true;
|
||||
}
|
||||
|
||||
stripNonAscii((uint8_t*) config.token, 37);
|
||||
stripNonAscii((uint8_t*) config.area, 17);
|
||||
stripNonAscii((uint8_t*) config.currency, 4);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_ENTSOE_START, config);
|
||||
bool ret = EEPROM.commit();
|
||||
@@ -504,6 +539,7 @@ void AmsConfiguration::clearEntsoe(EntsoeConfig& config) {
|
||||
strcpy(config.area, "");
|
||||
strcpy(config.currency, "");
|
||||
config.multiplier = 1000;
|
||||
config.enabled = false;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::isEntsoeChanged() {
|
||||
@@ -526,6 +562,7 @@ bool AmsConfiguration::getEnergyAccountingConfig(EnergyAccountingConfig& config)
|
||||
if(config.hours > 5) config.hours = 5;
|
||||
return true;
|
||||
} else {
|
||||
clearEnergyAccountingConfig(config);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -679,30 +716,6 @@ bool AmsConfiguration::hasConfig() {
|
||||
}
|
||||
} else {
|
||||
switch(configVersion) {
|
||||
case 90:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig90()) {
|
||||
configVersion = 91;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 91:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig91()) {
|
||||
configVersion = 92;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 92:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig92()) {
|
||||
configVersion = 93;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 93:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig93()) {
|
||||
@@ -795,61 +808,8 @@ void AmsConfiguration::saveTempSensors() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig90() {
|
||||
EntsoeConfig entsoe;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_ENTSOE_START_90, entsoe);
|
||||
EEPROM.put(CONFIG_ENTSOE_START, entsoe);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 91);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig91() {
|
||||
WiFiConfig91 wifi91;
|
||||
WiFiConfig wifi;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_WIFI_START_91, wifi91);
|
||||
strcpy(wifi.ssid, wifi91.ssid);
|
||||
strcpy(wifi.psk, wifi91.psk);
|
||||
strcpy(wifi.ip, wifi91.ip);
|
||||
strcpy(wifi.gateway, wifi91.gateway);
|
||||
strcpy(wifi.subnet, wifi91.subnet);
|
||||
strcpy(wifi.dns1, wifi91.dns1);
|
||||
strcpy(wifi.dns2, wifi91.dns2);
|
||||
strcpy(wifi.hostname, wifi91.hostname);
|
||||
wifi.mdns = wifi91.mdns;
|
||||
EEPROM.put(CONFIG_WIFI_START, wifi);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 92);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig92() {
|
||||
WiFiConfig wifi;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_WIFI_START, wifi);
|
||||
#if defined(ESP32)
|
||||
wifi.power = 195;
|
||||
#elif defined(ESP8266)
|
||||
wifi.power = 205;
|
||||
#endif
|
||||
EEPROM.put(CONFIG_WIFI_START, wifi);
|
||||
|
||||
EnergyAccountingConfig eac;
|
||||
clearEnergyAccountingConfig(eac);
|
||||
EEPROM.put(CONFIG_ENERGYACCOUNTING_START, eac);
|
||||
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 93);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig93() {
|
||||
MeterConfig meter;
|
||||
MeterConfig95 meter;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_METER_START_93, meter);
|
||||
meter.wattageMultiplier = 0;
|
||||
@@ -876,7 +836,7 @@ bool AmsConfiguration::relocateConfig94() {
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig95() {
|
||||
MeterConfig meter;
|
||||
MeterConfig95 meter;
|
||||
MeterConfig95 meter95;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_METER_START, meter);
|
||||
@@ -897,7 +857,7 @@ bool AmsConfiguration::relocateConfig96() {
|
||||
SystemConfig sys;
|
||||
EEPROM.get(CONFIG_SYSTEM_START, sys);
|
||||
|
||||
MeterConfig meter;
|
||||
MeterConfig100 meter;
|
||||
EEPROM.get(CONFIG_METER_START, meter);
|
||||
meter.source = 1; // Serial
|
||||
meter.parser = 0; // Auto
|
||||
|
||||
@@ -20,4 +20,17 @@ void fromHex(uint8_t *out, String in, uint16_t size) {
|
||||
for(int i = 0; i < size*2; i += 2) {
|
||||
out[i/2] = strtol(in.substring(i, i+2).c_str(), 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void stripNonAscii(uint8_t* in, uint16_t size) {
|
||||
for(uint16_t i = 0; i < size; i++) {
|
||||
if(in[i] == 0) { // Clear the rest with null-terminator
|
||||
memset(in+i, 0, size-i);
|
||||
break;
|
||||
}
|
||||
if(in[i] < 32 || in[i] > 126) {
|
||||
memset(in+i, ' ', 1);
|
||||
}
|
||||
}
|
||||
memset(in+size-1, 0, 1); // Make sure the last character is null-terminator
|
||||
}
|
||||
@@ -77,7 +77,7 @@ protected:
|
||||
unsigned long lastList2 = 0;
|
||||
uint8_t listType = 0, meterType = AmsTypeUnknown;
|
||||
time_t packageTimestamp = 0;
|
||||
String listId, meterId, meterModel;
|
||||
String listId = "", meterId = "", meterModel = "";
|
||||
time_t meterTimestamp = 0;
|
||||
uint16_t activeImportPower = 0, reactiveImportPower = 0, activeExportPower = 0, reactiveExportPower = 0;
|
||||
float l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0;
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-lg-row rounded shadow mt-2 mb-3" style="background-color: var(--purple);">
|
||||
<a href="/" class="">
|
||||
<h6 class="navbar-brand">AMS reader <small id="swVersion" data-url="https://api.github.com/repos/gskjold/AmsToMqttBridge/releases">${version}</small></h6>
|
||||
<h6 class="navbar-brand">AMS reader <small id="swVersion" data-url="https://api.github.com/repos/UtilitechAS/amsreader-firmware/releases">${version}</small></h6>
|
||||
</a>
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
@@ -66,7 +66,7 @@
|
||||
<a class="dropdown-item" href="/ntp">NTP</a>
|
||||
<a class="dropdown-item" href="/priceapi">Price API</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="https://github.com/gskjold/AmsToMqttBridge/wiki" target="_blank">Documentation</a>
|
||||
<a class="dropdown-item" href="https://github.com/UtilitechAS/amsreader-firmware/wiki" target="_blank">Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-lg-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<a class="nav-link p-2" href="https://github.com/UtilitechAS/amsreader-firmware" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<img class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" src="github.svg"/>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-sm-8">
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Known-hardware-configurations" target="_blank">Known hardware configurations</a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/Known-hardware-configurations" target="_blank">Known hardware configurations</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<a class="nav-link p-2" href="https://github.com/UtilitechAS/amsreader-firmware" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<img class="d-inline-block align-text-top" style="width: 2rem; height: 2rem;" src="github.svg"/>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small>${version}</small></h6></a>
|
||||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link p-2" href="https://github.com/gskjold/AmsToMqttBridge" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<a class="nav-link p-2" href="https://github.com/UtilitechAS/amsreader-firmware" target="_blank" rel="noopener" aria-label="GitHub">
|
||||
<img style="width: 2rem; height: 2rem;" src="github.svg"/>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1028,6 +1028,7 @@ void AmsWebServer::handleSetup() {
|
||||
|
||||
switch(sys.boardType) {
|
||||
case 0: // roarfred
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
@@ -1035,6 +1036,7 @@ void AmsWebServer::handleSetup() {
|
||||
gpioConfig->tempSensorPin = 5;
|
||||
break;
|
||||
case 1: // Arnio Kamstrup
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
@@ -1044,6 +1046,7 @@ void AmsWebServer::handleSetup() {
|
||||
gpioConfig->ledRgbInverted = true;
|
||||
break;
|
||||
case 2: // spenceme
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
@@ -1053,6 +1056,7 @@ void AmsWebServer::handleSetup() {
|
||||
wifi.sleep = 1;
|
||||
break;
|
||||
case 3: // Pow UART0
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
@@ -1063,6 +1067,7 @@ void AmsWebServer::handleSetup() {
|
||||
wifi.sleep = 1;
|
||||
break;
|
||||
case 4: // Pow GPIO12
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 12;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
@@ -1073,6 +1078,7 @@ void AmsWebServer::handleSetup() {
|
||||
wifi.sleep = 1;
|
||||
break;
|
||||
case 5: // Pow-K+ UART2
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 16;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPinRed = 13;
|
||||
@@ -1084,6 +1090,7 @@ void AmsWebServer::handleSetup() {
|
||||
wifi.sleep = 1;
|
||||
break;
|
||||
case 6: // Pow-P1
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 16;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPinRed = 13;
|
||||
@@ -1094,6 +1101,7 @@ void AmsWebServer::handleSetup() {
|
||||
gpioConfig->vccResistorVcc = 33;
|
||||
break;
|
||||
case 7: // Pow-U+
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->hanPin = 16;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPinRed = 13;
|
||||
@@ -1827,7 +1835,7 @@ void AmsWebServer::restartWaitHtml() {
|
||||
performRestart = false;
|
||||
} else if(performUpgrade) {
|
||||
WiFiClient client;
|
||||
String url = customFirmwareUrl.isEmpty() || !customFirmwareUrl.startsWith(F("http")) ? F("http://ams2mqtt.rewiredinvent.no/hub/firmware/update") : customFirmwareUrl;
|
||||
String url = customFirmwareUrl.isEmpty() || !customFirmwareUrl.startsWith(F("http")) ? F("http://hub.amsleser.no/hub/firmware/update") : customFirmwareUrl;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
@@ -89,8 +89,8 @@ private:
|
||||
EnergyAccountingConfig *config = NULL;
|
||||
Timezone *tz = NULL;
|
||||
uint8_t currentHour = 0, currentDay = 0, currentThresholdIdx = 0;
|
||||
double use, costHour, costDay;
|
||||
double produce, incomeHour, incomeDay;
|
||||
double use = 0, costHour = 0, costDay = 0;
|
||||
double produce = 0, incomeHour = 0, incomeDay = 0;
|
||||
EnergyAccountingData data = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
void calcDayCost();
|
||||
|
||||
@@ -185,7 +185,8 @@ double EnergyAccounting::getUseThisHour() {
|
||||
double EnergyAccounting::getUseToday() {
|
||||
float ret = 0.0;
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0;
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
if(tz == NULL) return 0.0;
|
||||
tmElements_t utc, local;
|
||||
breakTime(tz->toLocal(now), local);
|
||||
for(int i = 0; i < currentHour; i++) {
|
||||
@@ -197,7 +198,7 @@ double EnergyAccounting::getUseToday() {
|
||||
|
||||
double EnergyAccounting::getUseThisMonth() {
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0;
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
float ret = 0;
|
||||
for(int i = 0; i < currentDay; i++) {
|
||||
ret += ds->getDayImport(i) / 1000.0;
|
||||
@@ -212,7 +213,7 @@ double EnergyAccounting::getProducedThisHour() {
|
||||
double EnergyAccounting::getProducedToday() {
|
||||
float ret = 0.0;
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0;
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
tmElements_t utc;
|
||||
for(int i = 0; i < currentHour; i++) {
|
||||
breakTime(now - ((currentHour - i) * 3600), utc);
|
||||
@@ -223,7 +224,7 @@ double EnergyAccounting::getProducedToday() {
|
||||
|
||||
double EnergyAccounting::getProducedThisMonth() {
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0;
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
float ret = 0;
|
||||
for(int i = 0; i < currentDay; i++) {
|
||||
ret += ds->getDayExport(i) / 1000.0;
|
||||
@@ -279,6 +280,8 @@ uint8_t EnergyAccounting::getCurrentThreshold() {
|
||||
}
|
||||
|
||||
float EnergyAccounting::getMonthMax() {
|
||||
if(config == NULL)
|
||||
return 0.0;
|
||||
uint8_t count = 0;
|
||||
uint32_t maxHour = 0.0;
|
||||
bool included[5] = { false, false, false, false, false };
|
||||
@@ -308,6 +311,8 @@ float EnergyAccounting::getMonthMax() {
|
||||
}
|
||||
|
||||
EnergyAccountingPeak EnergyAccounting::getPeak(uint8_t num) {
|
||||
if(config == NULL)
|
||||
return EnergyAccountingPeak({0,0});
|
||||
if(num < 1 || num > 5) return EnergyAccountingPeak({0,0});
|
||||
|
||||
uint8_t count = 0;
|
||||
@@ -362,7 +367,9 @@ bool EnergyAccounting::load() {
|
||||
} else if(buf[0] == 4) {
|
||||
EnergyAccountingData4* data = (EnergyAccountingData4*) buf;
|
||||
this->data = { 5, data->month,
|
||||
(uint16_t) (data->costYesterday / 10), (uint16_t) (data->costThisMonth / 100), (uint16_t) (data->costLastMonth / 100),
|
||||
data->costYesterday,
|
||||
data->costThisMonth,
|
||||
data->costLastMonth,
|
||||
0,0,0, // Income from production
|
||||
data->peaks[0].day, data->peaks[0].value,
|
||||
data->peaks[1].day, data->peaks[1].value,
|
||||
|
||||
@@ -308,7 +308,7 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
} else if(hub) {
|
||||
String data;
|
||||
snprintf(buf, BufferSize, "%s/%s/%d/%d/%d?currency=%s",
|
||||
"http://ams2mqtt.rewiredinvent.no/hub/price",
|
||||
"http://hub.amsleser.no/hub/price",
|
||||
config->area,
|
||||
tm.Year+1970,
|
||||
tm.Month,
|
||||
|
||||
@@ -31,6 +31,5 @@ private:
|
||||
String clientId;
|
||||
String topic;
|
||||
HwTools* hw;
|
||||
uint8_t sequence = 0, listType = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@ const uint8_t HA_SENSOR_COUNT PROGMEM = 60;
|
||||
HomeAssistantSensor HA_SENSORS[HA_SENSOR_COUNT] PROGMEM = {
|
||||
{"Status", "/state", "rssi", "dBm", "signal_strength", "\"measurement\""},
|
||||
{"Supply volt", "/state", "vcc", "V", "voltage", "\"measurement\""},
|
||||
{"Temperature", "/state", "temp", "C", "temperature", "\"measurement\""},
|
||||
{"Temperature", "/state", "temp", "°C", "temperature", "\"measurement\""},
|
||||
{"Active import", "/power", "P", "W", "power", "\"measurement\""},
|
||||
{"L1 active import", "/power", "P1", "W", "power", "\"measurement\""},
|
||||
{"L2 active import", "/power", "P2", "W", "power", "\"measurement\""},
|
||||
|
||||
@@ -16,7 +16,6 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
|
||||
if(topic.isEmpty() || !mqtt->connected())
|
||||
return false;
|
||||
|
||||
listType = data->getListType(); // for discovery stuff in publishSystem()
|
||||
if(data->getListType() >= 3) { // publish energy counts
|
||||
snprintf_P(json, BufferSize, HA2_JSON,
|
||||
data->getActiveImportCounter(),
|
||||
@@ -192,6 +191,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
}
|
||||
|
||||
char ts1hr[24];
|
||||
memset(ts1hr, 0, 24);
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
|
||||
@@ -200,6 +200,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts3hr[24];
|
||||
memset(ts3hr, 0, 24);
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
|
||||
@@ -208,6 +209,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts6hr[24];
|
||||
memset(ts6hr, 0, 24);
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
|
||||
@@ -240,23 +242,19 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
|
||||
if(topic.isEmpty() || !mqtt->connected()){
|
||||
sequence = 0;
|
||||
if(topic.isEmpty() || !mqtt->connected())
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sequence % 3 == 0){
|
||||
snprintf_P(json, BufferSize, JSONSYS_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
VERSION
|
||||
);
|
||||
mqtt->publish(topic + "/state", json);
|
||||
}
|
||||
snprintf_P(json, BufferSize, JSONSYS_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
VERSION
|
||||
);
|
||||
mqtt->publish(topic + "/state", json);
|
||||
|
||||
if(!autodiscoverInit) {
|
||||
#if defined(ESP8266)
|
||||
@@ -315,6 +313,5 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ
|
||||
|
||||
autodiscoverInit = true;
|
||||
}
|
||||
if(listType>0) sequence++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,5 @@ private:
|
||||
String clientId;
|
||||
String topic;
|
||||
HwTools* hw;
|
||||
bool init = false;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -231,6 +231,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
}
|
||||
|
||||
char ts1hr[24];
|
||||
memset(ts1hr, 0, 24);
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
|
||||
@@ -239,6 +240,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts3hr[24];
|
||||
memset(ts3hr, 0, 24);
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
|
||||
@@ -247,6 +249,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts6hr[24];
|
||||
memset(ts6hr, 0, 24);
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
|
||||
@@ -279,7 +282,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
|
||||
if(init || topic.isEmpty() || !mqtt->connected())
|
||||
if(topic.isEmpty() || !mqtt->connected())
|
||||
return false;
|
||||
|
||||
snprintf_P(json, BufferSize, JSONSYS_JSON,
|
||||
@@ -291,6 +294,5 @@ bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounti
|
||||
hw->getTemperature(),
|
||||
VERSION
|
||||
);
|
||||
init = mqtt->publish(topic, json);
|
||||
return init;
|
||||
return mqtt->publish(topic, json);
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@
|
||||
{#if sysinfo.upgrading}
|
||||
<Mask active=true message="Device is upgrading, please wait"/>
|
||||
{:else if sysinfo.booting}
|
||||
<Mask active=true message="Device is booting, please wait"/>
|
||||
{#if sysinfo.trying}
|
||||
<Mask active=true message="Device is booting, please wait. Trying to reach it on {sysinfo.trying}"/>
|
||||
{:else}
|
||||
<Mask active=true message="Device is booting, please wait"/>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,54 +1,79 @@
|
||||
<script>
|
||||
export let data;
|
||||
export let currency;
|
||||
|
||||
let hasExport = data && (data.om || data.e > 0);
|
||||
export let hasExport;
|
||||
</script>
|
||||
|
||||
<div class="mx-2 text-sm">
|
||||
<strong>Real time calculation</strong>
|
||||
|
||||
{#if data && data.h !== undefined}
|
||||
<div class="flex">
|
||||
<div>Hour</div>
|
||||
<div class="flex-auto text-right">{data.h.u ? data.h.u.toFixed(2) : '-'} kWh {#if currency && (hasExport)}/ {data.h.c ? data.h.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Day</div>
|
||||
<div class="flex-auto text-right">{data.d.u ? data.d.u.toFixed(1) : '-'} kWh {#if currency && (hasExport)}/ {data.d.c ? data.d.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Month</div>
|
||||
<div class="flex-auto text-right">{data.m.u ? data.m.u.toFixed(0) : '-'} kWh {#if currency && (hasExport)}/ {data.m.c ? data.m.c.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
{#if hasExport}
|
||||
<div class="flex">
|
||||
<div>Hour</div>
|
||||
<div class="flex-auto text-right">{data.h.p ? data.h.p.toFixed(2) : '-'} kWh {#if currency}/ {data.h.i ? data.h.i.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Day</div>
|
||||
<div class="flex-auto text-right">{data.d.p ? data.d.p.toFixed(1) : '-'} kWh {#if currency}/ {data.d.i ? data.d.i.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Month</div>
|
||||
<div class="flex-auto text-right">{data.m.p ? data.m.p.toFixed(0) : '-'} kWh {#if currency}/ {data.m.i ? data.m.i.toFixed(2) : '-'} {currency}{/if}</div>
|
||||
</div>
|
||||
<br/><br/>
|
||||
|
||||
{#if data}
|
||||
{#if hasExport && currency}
|
||||
<strong>Import</strong>
|
||||
<div class="grid grid-cols-3 mb-3">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data.h.u ? data.h.u.toFixed(2) : '-'} kWh</div>
|
||||
<div class="text-right">{data.h.c ? data.h.c.toFixed(2) : '-'} {currency}</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data.d.u ? data.d.u.toFixed(1) : '-'} kWh</div>
|
||||
<div class="text-right">{data.d.c ? data.d.c.toFixed(1) : '-'} {currency}</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data.m.u ? data.m.u.toFixed(0) : '-'} kWh</div>
|
||||
<div class="text-right">{data.m.c ? data.m.c.toFixed(0) : '-'} {currency}</div>
|
||||
</div>
|
||||
<strong>Export</strong>
|
||||
<div class="grid grid-cols-3">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data.h.p ? data.h.p.toFixed(2) : '-'} kWh</div>
|
||||
<div class="text-right">{data.h.i ? data.h.i.toFixed(2) : '-'} {currency}</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data.d.p ? data.d.p.toFixed(1) : '-'} kWh</div>
|
||||
<div class="text-right">{data.d.i ? data.d.i.toFixed(1) : '-'} {currency}</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data.m.p ? data.m.p.toFixed(0) : '-'} kWh</div>
|
||||
<div class="text-right">{data.m.i ? data.m.i.toFixed(0) : '-'} {currency}</div>
|
||||
</div>
|
||||
{:else if hasExport}
|
||||
<strong>Import</strong>
|
||||
<div class="grid grid-cols-2 mb-3">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data.h.u ? data.h.u.toFixed(2) : '-'} kWh</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data.d.u ? data.d.u.toFixed(1) : '-'} kWh</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data.m.u ? data.m.u.toFixed(0) : '-'} kWh</div>
|
||||
</div>
|
||||
<strong>Export</strong>
|
||||
<div class="grid grid-cols-2">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data.h.p ? data.h.p.toFixed(2) : '-'} kWh</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data.d.p ? data.d.p.toFixed(1) : '-'} kWh</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data.m.p ? data.m.p.toFixed(0) : '-'} kWh</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex">
|
||||
<div>Hour</div>
|
||||
<div class="flex-auto text-right">{data.h.c ? data.h.c.toFixed(2) : '-'} {currency}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Day</div>
|
||||
<div class="flex-auto text-right">{data.d.c ? data.d.c.toFixed(2) : '-'} {currency}</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div>Month</div>
|
||||
<div class="flex-auto text-right">{data.m.c ? data.m.c.toFixed(2) : '-'} {currency}</div>
|
||||
</div>
|
||||
<strong>Consumption</strong>
|
||||
<div class="grid grid-cols-2 mb-3">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data.h.u ? data.h.u.toFixed(2) : '-'} kWh</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data.d.u ? data.d.u.toFixed(1) : '-'} kWh</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data.m.u ? data.m.u.toFixed(0) : '-'} kWh</div>
|
||||
</div>
|
||||
{#if currency}
|
||||
<strong>Cost</strong>
|
||||
<div class="grid grid-cols-2">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{data.h.c ? data.h.c.toFixed(2) : '-'} {currency}</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{data.d.c ? data.d.c.toFixed(1) : '-'} {currency}</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{data.m.c ? data.m.c.toFixed(0) : '-'} {currency}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -7,6 +7,7 @@
|
||||
import HelpIcon from './HelpIcon.svelte';
|
||||
import CountrySelectOptions from './CountrySelectOptions.svelte';
|
||||
import { Link, navigate } from 'svelte-navigator';
|
||||
import SubnetOptions from './SubnetOptions.svelte';
|
||||
|
||||
|
||||
export let sysinfo = {}
|
||||
@@ -67,8 +68,10 @@
|
||||
getConfiguration();
|
||||
|
||||
let isFactoryReset = false;
|
||||
let isFactoryResetComplete = false;
|
||||
async function factoryReset() {
|
||||
if(confirm("Are you sure you want to factory reset the device?")) {
|
||||
isFactoryReset = true;
|
||||
const data = new URLSearchParams();
|
||||
data.append("perform", "true");
|
||||
const response = await fetch('/reset', {
|
||||
@@ -76,7 +79,8 @@
|
||||
body: data
|
||||
});
|
||||
let res = (await response.json());
|
||||
isFactoryReset = res.success;
|
||||
isFactoryReset = false;
|
||||
isFactoryResetComplete = res.success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,12 +139,13 @@
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-2 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">General</strong>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/General-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="g" value="true"/>
|
||||
<div class="my-1">
|
||||
<div class="flex">
|
||||
<div>
|
||||
Hostname<br/>
|
||||
<input name="gh" bind:value={configuration.g.h} type="text" class="in-f w-full"/>
|
||||
<input name="gh" bind:value={configuration.g.h} type="text" class="in-f w-full" pattern="[A-Za-z0-9-]+"/>
|
||||
</div>
|
||||
<div>
|
||||
Time zone<br/>
|
||||
@@ -230,7 +235,7 @@
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Meter</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Meter-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/Meter-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="m" value="true"/>
|
||||
<div class="my-1">
|
||||
<span>Serial configuration</span>
|
||||
@@ -259,9 +264,8 @@
|
||||
<div class="my-1">
|
||||
Voltage<br/>
|
||||
<select name="md" bind:value={configuration.m.d} class="in-s">
|
||||
<option value={0}></option>
|
||||
<option value={1}>230V (IT/TT)</option>
|
||||
<option value={2}>400V (TN)</option>
|
||||
<option value={1}>230V (IT/TT)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="my-1 flex">
|
||||
@@ -320,7 +324,7 @@
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">WiFi</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/WiFi-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/WiFi-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="w" value="true"/>
|
||||
<div class="my-1">
|
||||
SSID<br/>
|
||||
@@ -354,7 +358,7 @@
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Network</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Network-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/Network-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<div class="my-1">
|
||||
IP<br/>
|
||||
<div class="flex">
|
||||
@@ -362,11 +366,9 @@
|
||||
<option value="dhcp">DHCP</option>
|
||||
<option value="static">Static</option>
|
||||
</select>
|
||||
<input name="ni" bind:value={configuration.n.i} type="text" class="in-m w-full" disabled={configuration.n.m == 'dhcp'}/>
|
||||
<select name="ns" bind:value={configuration.n.s} class="in-l" disabled={configuration.n.m == 'dhcp'}>
|
||||
<option value="255.255.255.0">/24</option>
|
||||
<option value="255.255.0.0">/16</option>
|
||||
<option value="255.0.0.0">/8</option>
|
||||
<input name="ni" bind:value={configuration.n.i} type="text" class="in-m w-full" disabled={configuration.n.m == 'dhcp'} required={configuration.n.m == 'static'}/>
|
||||
<select name="ns" bind:value={configuration.n.s} class="in-l" disabled={configuration.n.m == 'dhcp'} required={configuration.n.m == 'static'}>
|
||||
<SubnetOptions/>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -396,7 +398,7 @@
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">MQTT</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/MQTT-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/MQTT-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="q" value="true"/>
|
||||
<div class="my-1">
|
||||
Server
|
||||
@@ -471,7 +473,7 @@
|
||||
{#if configuration.q.m == 3}
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Domoticz</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/MQTT-configuration#domoticz" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/MQTT-configuration#domoticz" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="o" value="true"/>
|
||||
<div class="my-1 flex">
|
||||
<div class="w-1/2">
|
||||
@@ -488,7 +490,7 @@
|
||||
<div class="flex">
|
||||
<input name="ou1" bind:value={configuration.o.u1} type="text" class="in-f tr w-1/3"/>
|
||||
<input name="ou2" bind:value={configuration.o.u2} type="text" class="in-m tr w-1/3"/>
|
||||
<input name="ou2" bind:value={configuration.o.u3} type="text" class="in-l tr w-1/3"/>
|
||||
<input name="ou3" bind:value={configuration.o.u3} type="text" class="in-l tr w-1/3"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -496,7 +498,7 @@
|
||||
{#if configuration.p.r.startsWith("10YNO") || configuration.p.r == '10Y1001A1001A48H'}
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Tariff thresholds</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Threshold-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/Threshold-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="t" value="true"/>
|
||||
<div class="flex flex-wrap my-1">
|
||||
<label class="flex w-40 m-1">
|
||||
@@ -554,6 +556,7 @@
|
||||
{/if}
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">User interface</strong>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/User-interface" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="u" value="true"/>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="w-1/2">
|
||||
@@ -649,7 +652,7 @@
|
||||
{#if sysinfo.board > 20 || sysinfo.chip == 'esp8266'}
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">Hardware</strong>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/GPIO-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/GPIO-configuration" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
{#if sysinfo.board > 20}
|
||||
<input type="hidden" name="i" value="true"/>
|
||||
<div class="flex flex-wrap">
|
||||
@@ -764,4 +767,5 @@
|
||||
|
||||
<Mask active={loading} message="Loading configuration"/>
|
||||
<Mask active={saving} message="Saving configuration"/>
|
||||
<Mask active={isFactoryReset} message="Device have been factory reset and switched to AP mode"/>
|
||||
<Mask active={isFactoryReset} message="Performing factory reset"/>
|
||||
<Mask active={isFactoryResetComplete} message="Device have been factory reset and switched to AP mode"/>
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<hr/>
|
||||
<div class="my-3">
|
||||
Enable one-click upgrade? (implies data collection)<br/>
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki/Data-collection-on-one-click-firmware-upgrade" target="_blank" class="text-blue-600 hover:text-blue-800">Read more</a><br/>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki/Data-collection-on-one-click-firmware-upgrade" target="_blank" class="text-blue-600 hover:text-blue-800">Read more</a><br/>
|
||||
<label><input type="radio" name="sf" value={1} checked={sysinfo.fwconsent === 1} class="rounded m-2" required/> Yes</label><label><input type="radio" name="sf" value={2} checked={sysinfo.fwconsent === 2} class="rounded m-2" required/> No</label><br/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { pricesStore, dayPlotStore, monthPlotStore, temperaturesStore } from './DataStores.js';
|
||||
import { metertype, uiVisibility } from './Helpers.js';
|
||||
import { ampcol, exportcol, metertype, uiVisibility } from './Helpers.js';
|
||||
import PowerGauge from './PowerGauge.svelte';
|
||||
import VoltPlot from './VoltPlot.svelte';
|
||||
import AmpPlot from './AmpPlot.svelte';
|
||||
@@ -32,23 +32,23 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="grid xl:grid-cols-6 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2">
|
||||
<div class="grid 2xl:grid-cols-6 xl:grid-cols-5 lg:grid-cols-4 md:grid-cols-3 sm:grid-cols-2">
|
||||
{#if uiVisibility(sysinfo.ui.i, data.i)}
|
||||
<div class="cnt">
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="col-span-2">
|
||||
<PowerGauge val={data.i ? data.i : 0} max={data.im} unit="W" label="Import" sub={data.p} subunit={prices.currency}/>
|
||||
<div class="cnt">
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="col-span-2">
|
||||
<PowerGauge val={data.i ? data.i : 0} max={data.im ? data.im : 15000} unit="W" label="Import" sub={data.p} subunit={prices.currency} colorFn={ampcol}/>
|
||||
</div>
|
||||
<div>{data.mt ? metertype(data.mt) : '-'}</div>
|
||||
<div class="text-right">{data.ic ? data.ic.toFixed(1) : '-'} kWh</div>
|
||||
</div>
|
||||
<div>{data.mt ? metertype(data.mt) : '-'}</div>
|
||||
<div class="text-right">{data.ic ? data.ic.toFixed(1) : '-'} kWh</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.e, data.om || data.e > 0)}
|
||||
<div class="cnt">
|
||||
<div class="grid grid-cols-2">
|
||||
<div class="col-span-2">
|
||||
<PowerGauge val={data.e ? data.e : 0} max={data.om ? data.om : 10000} unit="W" label="Export"/>
|
||||
<PowerGauge val={data.e ? data.e : 0} max={data.om ? data.om * 1000 : 10000} unit="W" label="Export" colorFn={exportcol}/>
|
||||
</div>
|
||||
<div></div>
|
||||
<div class="text-right">{data.ec ? data.ec.toFixed(1) : '-'} kWh</div>
|
||||
@@ -56,48 +56,48 @@
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.v, data.u1 > 100 || data.u2 > 100 || data.u3 > 100)}
|
||||
<div class="cnt">
|
||||
<VoltPlot u1={data.u1} u2={data.u2} u3={data.u3} ds={data.ds}/>
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<VoltPlot u1={data.u1} u2={data.u2} u3={data.u3} ds={data.ds}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.a, data.i1 > 0.01 || data.i2 > 0.01 || data.i3 > 0.01)}
|
||||
<div class="cnt">
|
||||
<AmpPlot u1={data.u1} u2={data.u2} u3={data.u3} i1={data.i1} i2={data.i2} i3={data.i3} max={data.mf ? data.mf : 32}/>
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<AmpPlot u1={data.u1} u2={data.u2} u3={data.u3} i1={data.i1} i2={data.i2} i3={data.i3} max={data.mf ? data.mf : 32}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.r, data.ri > 0 || data.re > 0 || data.ric > 0 || data.rec > 0)}
|
||||
<div class="cnt">
|
||||
<ReactiveData importInstant={data.ri} exportInstant={data.re} importTotal={data.ric} exportTotal={data.rec}/>
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<ReactiveData importInstant={data.ri} exportInstant={data.re} importTotal={data.ric} exportTotal={data.rec}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.c, data.ea)}
|
||||
<div class="cnt">
|
||||
<AccountingData data={data.ea} currency={prices.currency}/>
|
||||
</div>
|
||||
<div class="cnt">
|
||||
<AccountingData data={data.ea} currency={prices.currency} hasExport={data.om > 0 || data.e > 0}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if data && data.pr && (data.pr.startsWith("10YNO") || data.pr == '10Y1001A1001A48H')}
|
||||
<div class="cnt h-64">
|
||||
<TariffPeakChart />
|
||||
</div>
|
||||
{#if uiVisibility(sysinfo.ui.t, data.pr && (data.pr.startsWith("10YNO") || data.pr == '10Y1001A1001A48H'))}
|
||||
<div class="cnt h-64">
|
||||
<TariffPeakChart />
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.p, (typeof data.p == "number") && !Number.isNaN(data.p))}
|
||||
<div class="cnt xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<div class="cnt 2xl:col-span-6 xl:col-span-5 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<PricePlot json={prices}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.d, dayPlot)}
|
||||
<div class="cnt xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<DayPlot json={dayPlot} />
|
||||
</div>
|
||||
<div class="cnt 2xl:col-span-6 xl:col-span-5 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<DayPlot json={dayPlot} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.m, monthPlot)}
|
||||
<div class="cnt xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<MonthPlot json={monthPlot} />
|
||||
</div>
|
||||
<div class="cnt 2xl:col-span-6 xl:col-span-5 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<MonthPlot json={monthPlot} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.s, data.t && data.t != -127 && temperatures.c > 1)}
|
||||
<div class="cnt xl:col-span-6 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<TemperaturePlot json={temperatures} />
|
||||
</div>
|
||||
<div class="cnt 2xl:col-span-6 xl:col-span-5 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64">
|
||||
<TemperaturePlot json={temperatures} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -25,7 +25,8 @@ let sysinfo = {
|
||||
booting: false,
|
||||
upgrading: false,
|
||||
ui: {},
|
||||
security: 0
|
||||
security: 0,
|
||||
trying: null
|
||||
};
|
||||
export const sysinfoStore = writable(sysinfo);
|
||||
export async function getSysinfo() {
|
||||
@@ -177,7 +178,7 @@ let releases = [];
|
||||
export const gitHubReleaseStore = writable(releases);
|
||||
|
||||
export async function getGitHubReleases() {
|
||||
const response = await fetchWithTimeout("https://api.github.com/repos/gskjold/AmsToMqttBridge/releases");
|
||||
const response = await fetchWithTimeout("https://api.github.com/repos/UtilitechAS/amsreader-firmware/releases");
|
||||
releases = (await response.json())
|
||||
gitHubReleaseStore.set(releases);
|
||||
};
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
{/if}
|
||||
<div class="flex-auto p-2 flex flex-row-reverse flex-wrap">
|
||||
<div class="flex-none">
|
||||
<a class="float-right" href='https://github.com/gskjold/AmsToMqttBridge' target='_blank' rel="noreferrer" aria-label="GitHub"><img class="gh-logo" src={GitHubLogo} alt="GitHub repo"/></a>
|
||||
<a class="float-right" href='https://github.com/UtilitechAS/amsreader-firmware' target='_blank' rel="noreferrer" aria-label="GitHub"><img class="gh-logo" src={GitHubLogo} alt="GitHub repo"/></a>
|
||||
</div>
|
||||
<div class="flex-none my-auto px-2">
|
||||
<Clock timestamp={ data.c ? new Date(data.c * 1000) : new Date(0) } />
|
||||
@@ -84,7 +84,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="flex-none px-1 mt-1" title="Documentation">
|
||||
<a href="https://github.com/gskjold/AmsToMqttBridge/wiki" target='_blank' rel="noreferrer"><HelpIcon/></a>
|
||||
<a href="https://github.com/UtilitechAS/amsreader-firmware/wiki" target='_blank' rel="noreferrer"><HelpIcon/></a>
|
||||
</div>
|
||||
{#if sysinfo.fwconsent === 1 && nextVersion}
|
||||
<div class="flex-none mr-3 text-yellow-500" title="New version: {nextVersion.tag_name}">
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
export let monthnames = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||
|
||||
export function voltcol(pct) {
|
||||
if(pct > 85) return '#d90000';
|
||||
else if(pct > 75) return'#e32100';
|
||||
else if(pct > 70) return '#ffb800';
|
||||
else if(pct > 65) return '#dcd800';
|
||||
else if(pct > 35) return '#32d900';
|
||||
else if(pct > 25) return '#dcd800';
|
||||
else if(pct > 20) return '#ffb800';
|
||||
else if(pct > 15) return'#e32100';
|
||||
else return '#d90000';
|
||||
export function voltcol(volt) {
|
||||
if(volt > 218 && volt < 242) return '#32d900';
|
||||
if(volt > 212 && volt < 248) return '#b1d900';
|
||||
if(volt > 208 && volt < 252) return '#ffb800';
|
||||
return '#d90000';
|
||||
};
|
||||
|
||||
export function ampcol(pct) {
|
||||
@@ -20,6 +15,13 @@ export function ampcol(pct) {
|
||||
else return '#32d900';
|
||||
};
|
||||
|
||||
export function exportcol(pct) {
|
||||
if(pct > 75) return '#32d900';
|
||||
else if(pct > 50) return '#77d900';
|
||||
else if(pct > 25) return '#94d900';
|
||||
else return '#dcd800';
|
||||
};
|
||||
|
||||
export function metertype(mt) {
|
||||
switch(mt) {
|
||||
case 1:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script>
|
||||
import PowerGaugeSvg from './PowerGaugeSvg.svelte';
|
||||
import { ampcol } from './Helpers.js';
|
||||
|
||||
export let val;
|
||||
export let max;
|
||||
@@ -8,10 +7,16 @@
|
||||
export let label;
|
||||
export let sub = "";
|
||||
export let subunit = "";
|
||||
export let colorFn;
|
||||
|
||||
let pct = 0;
|
||||
$: {
|
||||
pct = (Math.min(val,max)/max) * 100
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="pl-root">
|
||||
<PowerGaugeSvg pct={val/max * 100} color={ampcol(val/max * 100)}/>
|
||||
<PowerGaugeSvg pct={pct} color={colorFn(pct)}/>
|
||||
<span class="pl-ov">
|
||||
<span class="pl-lab">{label}</span>
|
||||
<br/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import Mask from './Mask.svelte'
|
||||
import SubnetOptions from './SubnetOptions.svelte';
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
@@ -12,7 +13,15 @@
|
||||
var url = "";
|
||||
tries++;
|
||||
|
||||
var retry = function() {
|
||||
setTimeout(scanForDevice, 1000);
|
||||
};
|
||||
|
||||
if(sysinfo.net.ip && tries%3 == 0) {
|
||||
if(sysinfo.net.ip == '0.0.0.0') {
|
||||
retry();
|
||||
return;
|
||||
};
|
||||
url = "http://" + sysinfo.net.ip;
|
||||
} else if(sysinfo.hostname && tries%3 == 1) {
|
||||
url = "http://" + sysinfo.hostname;
|
||||
@@ -22,10 +31,10 @@
|
||||
url = "";
|
||||
}
|
||||
if(console) console.log("Trying url " + url);
|
||||
|
||||
var retry = function() {
|
||||
setTimeout(scanForDevice, 1000);
|
||||
};
|
||||
sysinfoStore.update(s => {
|
||||
s.trying = url;
|
||||
return s;
|
||||
});
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.timeout = 5000;
|
||||
@@ -42,12 +51,10 @@
|
||||
async function handleSubmit(e) {
|
||||
loadingOrSaving = true;
|
||||
const formData = new FormData(e.target);
|
||||
let hostname = sysinfo.hostname;
|
||||
const data = new URLSearchParams();
|
||||
for (let field of formData) {
|
||||
const [key, value] = field;
|
||||
data.append(key, value)
|
||||
if(key == 'sh') hostname = value;
|
||||
}
|
||||
|
||||
const response = await fetch('/save', {
|
||||
@@ -58,9 +65,15 @@
|
||||
loadingOrSaving = false;
|
||||
|
||||
sysinfoStore.update(s => {
|
||||
s.hostname = hostname;
|
||||
s.hostname = formData.get('sh');
|
||||
s.usrcfg = res.success;
|
||||
s.booting = res.reboot;
|
||||
if(staticIp) {
|
||||
s.net.ip = formData.get('si');
|
||||
s.net.mask = formData.get('su');
|
||||
s.net.gw = formData.get('sg');
|
||||
s.net.dns1 = formData.get('sd');
|
||||
}
|
||||
setTimeout(scanForDevice, 5000);
|
||||
return s;
|
||||
});
|
||||
@@ -70,20 +83,20 @@
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
<div class="cnt">
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<form on:submit|preventDefault={handleSubmit}>
|
||||
<input type="hidden" name="s" value="true"/>
|
||||
<strong class="text-sm">Setup</strong>
|
||||
<div class="my-3">
|
||||
SSID<br/>
|
||||
<input name="ss" type="text" class="in-s"/>
|
||||
<input name="ss" type="text" class="in-s" required/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
PSK<br/>
|
||||
<input name="sp" type="password" class="in-s"/>
|
||||
<input name="sp" type="password" class="in-s" autocomplete="off"/>
|
||||
</div>
|
||||
<div>
|
||||
Hostname:
|
||||
<input name="sh" bind:value={sysinfo.hostname} type="text" class="in-s" maxlength="32" pattern="[a-z0-9_-]+" placeholder="Optional, ex.: ams-reader"/>
|
||||
Hostname
|
||||
<input name="sh" bind:value={sysinfo.hostname} type="text" class="in-s" maxlength="32" pattern="[a-z0-9_-]+" placeholder="Optional, ex.: ams-reader" autocomplete="off"/>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<label><input type="checkbox" name="sm" value="static" class="rounded mb-1" bind:checked={staticIp} /> Static IP</label>
|
||||
@@ -92,9 +105,7 @@
|
||||
<div class="flex">
|
||||
<input name="si" type="text" class="in-f w-full" required={staticIp}/>
|
||||
<select name="su" class="in-l" required={staticIp}>
|
||||
<option value="255.255.255.0">/24</option>
|
||||
<option value="255.255.0.0">/16</option>
|
||||
<option value="255.0.0.0">/8</option>
|
||||
<SubnetOptions/>
|
||||
</select>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
16
lib/SvelteUi/app/src/lib/SubnetOptions.svelte
Normal file
@@ -0,0 +1,16 @@
|
||||
<optgroup label="Most common is /24 (255.255.255.0)">
|
||||
<option value="255.255.255.0">/24</option>
|
||||
</optgroup>
|
||||
<optgroup label="Smaller subnets">
|
||||
<option value="255.255.255.128">/25</option>
|
||||
<option value="255.255.255.192">/26</option>
|
||||
<option value="255.255.255.224">/27</option>
|
||||
<option value="255.255.255.240">/28</option>
|
||||
<option value="255.255.255.248">/29</option>
|
||||
</optgroup>
|
||||
<optgroup label="Larger subnets">
|
||||
<option value="255.255.254.0">/23</option>
|
||||
<option value="255.255.252.0">/22</option>
|
||||
<option value="255.255.0.0">/16</option>
|
||||
</optgroup>
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
<option value={13}>GPIO13</option>
|
||||
<option value={14}>GPIO14</option>
|
||||
<option value={15}>GPIO15</option>
|
||||
|
||||
{#if chip == 'esp32s2'}
|
||||
<option value={16}>GPIO16</option>
|
||||
{/if}
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={17}>GPIO17</option>
|
||||
{#if chip != 'esp32s2'}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
points.push({
|
||||
label: u1 ? u1.toFixed(0) + 'V' : '-',
|
||||
value: u1 ? u1 : 0,
|
||||
color: voltcol(u1 ? (u1-min)/(max-min)*100 : 0)
|
||||
color: voltcol(u1 ? u1 : 0)
|
||||
});
|
||||
}
|
||||
if(u2 > 0) {
|
||||
@@ -27,7 +27,7 @@
|
||||
points.push({
|
||||
label: u2 ? u2.toFixed(0) + 'V' : '-',
|
||||
value: u2 ? u2 : 0,
|
||||
color: voltcol(u2 ? (u2-min)/(max-min)*100 : 0)
|
||||
color: voltcol(u2 ? u2 : 0)
|
||||
});
|
||||
}
|
||||
if(u3 > 0) {
|
||||
@@ -35,7 +35,7 @@
|
||||
points.push({
|
||||
label: u3 ? u3.toFixed(0) + 'V' : '-',
|
||||
value: u3 ? u3 : 0,
|
||||
color: voltcol(u3 ? (u3-min)/(max-min)*100 : 0)
|
||||
color: voltcol(u3 ? u3 : 0)
|
||||
});
|
||||
}
|
||||
config = {
|
||||
|
||||
@@ -17,18 +17,18 @@ export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.229",
|
||||
"/energyprice.json": "http://192.168.233.229",
|
||||
"/dayplot.json": "http://192.168.233.229",
|
||||
"/monthplot.json": "http://192.168.233.229",
|
||||
"/temperature.json": "http://192.168.233.229",
|
||||
"/sysinfo.json": "http://192.168.233.229",
|
||||
"/configuration.json": "http://192.168.233.229",
|
||||
"/tariff.json": "http://192.168.233.229",
|
||||
"/save": "http://192.168.233.229",
|
||||
"/reboot": "http://192.168.233.229",
|
||||
"/configfile": "http://192.168.233.229",
|
||||
"/upgrade": "http://192.168.233.229"
|
||||
"/data.json": "http://192.168.233.244",
|
||||
"/energyprice.json": "http://192.168.233.244",
|
||||
"/dayplot.json": "http://192.168.233.244",
|
||||
"/monthplot.json": "http://192.168.233.244",
|
||||
"/temperature.json": "http://192.168.233.244",
|
||||
"/sysinfo.json": "http://192.168.233.244",
|
||||
"/configuration.json": "http://192.168.233.244",
|
||||
"/tariff.json": "http://192.168.233.244",
|
||||
"/save": "http://192.168.233.244",
|
||||
"/reboot": "http://192.168.233.244",
|
||||
"/configfile": "http://192.168.233.244",
|
||||
"/upgrade": "http://192.168.233.244"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ static const char HEADER_LOCATION[] PROGMEM = "Location";
|
||||
|
||||
static const char CACHE_CONTROL_NO_CACHE[] PROGMEM = "no-cache, no-store, must-revalidate";
|
||||
static const char CACHE_1HR[] PROGMEM = "public, max-age=3600";
|
||||
static const char CACHE_1MO[] PROGMEM = "public, max-age=2592000";
|
||||
static const char PRAGMA_NO_CACHE[] PROGMEM = "no-cache";
|
||||
static const char EXPIRES_OFF[] PROGMEM = "-1";
|
||||
static const char AUTHENTICATE_BASIC[] PROGMEM = "Basic realm=\"Secure Area\"";
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
<html>
|
||||
<form action="/firmware" enctype="multipart/form-data" method="post" autocomplete="off">
|
||||
File: <input name="file" type="file" accept=".bin">
|
||||
<button type="submit" class="">Upload</button>
|
||||
</form>
|
||||
or<br/><br/>
|
||||
<form action="/firmware" method="post" autocomplete="off">
|
||||
URL: <input name="url" type="text"/>
|
||||
<button type="submit" class="">Install</button>
|
||||
</form>
|
||||
<body>
|
||||
<fieldset>
|
||||
<legend>Firmware install</legend>
|
||||
<form action="/firmware" enctype="multipart/form-data" method="post" autocomplete="off">
|
||||
File: <input name="file" type="file" accept=".bin">
|
||||
<button type="submit">Upload</button>
|
||||
</form>
|
||||
or<br/><br/>
|
||||
<form action="/firmware" method="post" autocomplete="off">
|
||||
URL: <input name="url" type="text"/>
|
||||
<button type="submit">Install</button>
|
||||
</form>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Configuration upload</legend>
|
||||
<form action="/configfile" enctype="multipart/form-data" method="post">
|
||||
File: <input name="file" type="file" accept=".cfg">
|
||||
<button type="submit">Upload</button>
|
||||
</form>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Factory reset</legend>
|
||||
<form action="/reset" method="post">
|
||||
<button type="submit" name="perform" value="true">Perform factory reset</button>
|
||||
</form>
|
||||
</fieldset>
|
||||
</body>
|
||||
</html>
|
||||
@@ -240,12 +240,22 @@ void AmsWebServer::sysinfoJson() {
|
||||
UiConfig ui;
|
||||
config->getUiConfig(ui);
|
||||
|
||||
snprintf_P(buf, BufferSize, SYSINFO_JSON,
|
||||
String meterModel = meterState->getMeterModel();
|
||||
if(!meterModel.isEmpty())
|
||||
meterModel.replace("\\", "\\\\");
|
||||
|
||||
String meterId = meterState->getMeterId();
|
||||
if(!meterId.isEmpty())
|
||||
meterId.replace("\\", "\\\\");
|
||||
|
||||
int size = snprintf_P(buf, BufferSize, SYSINFO_JSON,
|
||||
VERSION,
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
"esp32s2",
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
"esp32c3",
|
||||
#elif defined(CONFIG_FREERTOS_UNICORE)
|
||||
"esp32solo",
|
||||
#elif defined(ESP32)
|
||||
"esp32",
|
||||
#elif defined(ESP8266)
|
||||
@@ -272,8 +282,8 @@ void AmsWebServer::sysinfoJson() {
|
||||
dns2.toString().c_str(),
|
||||
#endif
|
||||
meterState->getMeterType(),
|
||||
meterState->getMeterModel().c_str(),
|
||||
meterState->getMeterId().c_str(),
|
||||
meterModel.c_str(),
|
||||
meterId.c_str(),
|
||||
ui.showImport,
|
||||
ui.showExport,
|
||||
ui.showVoltage,
|
||||
@@ -288,6 +298,8 @@ void AmsWebServer::sysinfoJson() {
|
||||
webConfig.security
|
||||
);
|
||||
|
||||
stripNonAscii((uint8_t*) buf, size+1);
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
|
||||
server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
|
||||
@@ -346,7 +358,6 @@ void AmsWebServer::dataJson() {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
uint8_t hanStatus;
|
||||
if(meterState->getLastError() != 0) {
|
||||
hanStatus = 3;
|
||||
@@ -395,7 +406,7 @@ void AmsWebServer::dataJson() {
|
||||
snprintf_P(buf, BufferSize, DATA_JSON,
|
||||
maxPwr == 0 ? meterState->isThreePhase() ? 20000 : 10000 : maxPwr,
|
||||
meterConfig->productionCapacity,
|
||||
meterConfig->mainFuse == 0 ? 32 : meterConfig->mainFuse,
|
||||
meterConfig->mainFuse == 0 ? 40 : meterConfig->mainFuse,
|
||||
meterState->getActiveImportPower(),
|
||||
meterState->getActiveExportPower(),
|
||||
meterState->getReactiveImportPower(),
|
||||
@@ -442,7 +453,7 @@ void AmsWebServer::dataJson() {
|
||||
ea->getCostThisMonth(),
|
||||
ea->getProducedThisMonth(),
|
||||
ea->getIncomeThisMonth(),
|
||||
priceRegion.c_str(),
|
||||
eapi == NULL ? "" : priceRegion.c_str(),
|
||||
meterState->getLastError(),
|
||||
eapi == NULL ? 0 : eapi->getLastError(),
|
||||
(uint32_t) now,
|
||||
@@ -722,7 +733,7 @@ void AmsWebServer::indexCss() {
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1HR);
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1MO);
|
||||
server.setContentLength(INDEX_CSS_LEN);
|
||||
server.send_P(200, MIME_CSS, INDEX_CSS);
|
||||
}
|
||||
@@ -733,7 +744,7 @@ void AmsWebServer::indexJs() {
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1HR);
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1MO);
|
||||
server.setContentLength(INDEX_JS_LEN);
|
||||
server.send_P(200, MIME_JS, INDEX_JS);
|
||||
}
|
||||
@@ -981,7 +992,7 @@ void AmsWebServer::handleSave() {
|
||||
switch(boardType) {
|
||||
case 2: // spenceme
|
||||
config->clearGpio(*gpioConfig);
|
||||
gpioConfig->vccBootLimit = 33;
|
||||
gpioConfig->vccBootLimit = 32;
|
||||
gpioConfig->hanPin = 3;
|
||||
gpioConfig->apPin = 0;
|
||||
gpioConfig->ledPin = 2;
|
||||
@@ -1035,16 +1046,18 @@ void AmsWebServer::handleSave() {
|
||||
success = false;
|
||||
}
|
||||
#endif
|
||||
config->setGpioConfig(*gpioConfig);
|
||||
if(success) {
|
||||
config->setGpioConfig(*gpioConfig);
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
sys.boardType = success ? boardType : 0xFF;
|
||||
sys.vendorConfigured = success;
|
||||
config->setSystemConfig(sys);
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
sys.boardType = success ? boardType : 0xFF;
|
||||
sys.vendorConfigured = success;
|
||||
config->setSystemConfig(sys);
|
||||
}
|
||||
}
|
||||
|
||||
if(server.hasArg(F("s")) && server.arg(F("s")) == F("true")) {
|
||||
if(server.hasArg(F("s")) && server.arg(F("s")) == F("true") && server.hasArg(F("ss")) && !server.arg(F("ss")).isEmpty()) {
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
|
||||
@@ -1435,7 +1448,7 @@ void AmsWebServer::upgrade() {
|
||||
customFirmwareUrl = server.arg(F("url"));
|
||||
}
|
||||
|
||||
String url = customFirmwareUrl.isEmpty() || !customFirmwareUrl.startsWith(F("http")) ? F("http://ams2mqtt.rewiredinvent.no/hub/firmware/update") : customFirmwareUrl;
|
||||
String url = customFirmwareUrl.isEmpty() || !customFirmwareUrl.startsWith(F("http")) ? F("http://hub.amsleser.no/hub/firmware/update") : customFirmwareUrl;
|
||||
|
||||
if(server.hasArg(F("version"))) {
|
||||
url += "/" + server.arg(F("version"));
|
||||
|
||||
@@ -2,19 +2,16 @@
|
||||
default_envs = dev
|
||||
|
||||
[env:dev]
|
||||
platform = espressif8266
|
||||
platform = espressif8266@3.2.0
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
board_build.ldscript = eagle.flash.4m2m.ld
|
||||
framework = arduino
|
||||
lib_deps = ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
build_flags = ${common.build_flags} -D DEBUG_MODE=1
|
||||
lib_ldf_mode = off
|
||||
lib_compat_mode = off
|
||||
build_flags =
|
||||
-D WEBSOCKET_DISABLED=1
|
||||
-D DEBUG_MODE=1
|
||||
extra_scripts =
|
||||
pre:scripts/addversion.py
|
||||
scripts/makeweb.py
|
||||
lib_deps = ESP8266WiFi, ESP8266mDNS, ESP8266WebServer, ESP8266HTTPClient, ESP8266httpUpdate, ${common.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
monitor_speed = 115200 ; If serial port is shared with HAN, use baud and parity configured for meter
|
||||
monitor_flags =
|
||||
--parity
|
||||
|
||||
40
scripts/esp32c3/flash.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$1" ];then
|
||||
echo "Usage: "
|
||||
echo " Flashing first time : $0 flash /dev/ttyUSB0"
|
||||
echo " When upgrading to new version : $0 upgrade /dev/ttyUSB0"
|
||||
echo " NOTE: Replace /dev/ttyUSB0 with correct port"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$2" ];then
|
||||
echo "Please specify port"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
esptool=`which esptool`
|
||||
if [ -z "$esptool" ];then
|
||||
esptool=`which esptool.py`
|
||||
fi
|
||||
if [ -z "$esptool" ];then
|
||||
if [ -f esptool.py ];then
|
||||
esptool="esptool.py"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$esptool" ];then
|
||||
echo "esptool.py not available to run following command: "
|
||||
esptool="echo esptool.py"
|
||||
fi
|
||||
|
||||
if [ "$1" = "flash" ];then
|
||||
$esptool --chip esp32c3 --port $2 --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect \
|
||||
0x1000 bootloader_qio_40m.bin \
|
||||
0x8000 partitions.bin \
|
||||
0xe000 boot_app0.bin \
|
||||
0x10000 firmware.bin
|
||||
exit $?
|
||||
elif [ "$1" = "upgrade" ];then
|
||||
$esptool --chip esp32c3 --port $2 --baud 460800 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x10000 firmware.bin
|
||||
exit $?
|
||||
fi
|
||||
14
scripts/esp32c3/mkzip.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
env="esp32c3"
|
||||
build_dir=".pio/build/$env/"
|
||||
|
||||
if [ ! -d $build_dir ];then
|
||||
echo "No build directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/sdk/$env/bin/bootloader_qio_40m.bin $build_dir
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin $build_dir
|
||||
chmod +x scripts/$env/flash.sh
|
||||
zip -j $env.zip $build_dir/*.bin scripts/$env/flash.sh
|
||||
@@ -122,45 +122,10 @@ DSMRParser *dsmrParser = NULL;
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
config.hasConfig(); // Need to run this to make sure all configuration have been migrated before we load GPIO config
|
||||
|
||||
if(!config.getGpioConfig(gpioConfig)) {
|
||||
#if HW_ROARFRED
|
||||
gpioConfig.hanPin = 3;
|
||||
gpioConfig.apPin = 0;
|
||||
gpioConfig.ledPin = 2;
|
||||
gpioConfig.ledInverted = true;
|
||||
gpioConfig.tempSensorPin = 5;
|
||||
#elif defined(ARDUINO_ESP8266_WEMOS_D1MINI)
|
||||
gpioConfig.hanPin = 5;
|
||||
gpioConfig.apPin = 4;
|
||||
gpioConfig.ledPin = 2;
|
||||
gpioConfig.ledInverted = true;
|
||||
gpioConfig.tempSensorPin = 14;
|
||||
gpioConfig.vccMultiplier = 1100;
|
||||
#elif defined(ARDUINO_LOLIN_D32)
|
||||
gpioConfig.hanPin = 16;
|
||||
gpioConfig.ledPin = 5;
|
||||
gpioConfig.ledInverted = true;
|
||||
gpioConfig.tempSensorPin = 14;
|
||||
#elif defined(ARDUINO_FEATHER_ESP32)
|
||||
gpioConfig.hanPin = 16;
|
||||
gpioConfig.ledPin = 2;
|
||||
gpioConfig.tempSensorPin = 14;
|
||||
#elif defined(ARDUINO_ESP32_DEV)
|
||||
gpioConfig.hanPin = 16;
|
||||
gpioConfig.ledPin = 2;
|
||||
gpioConfig.ledInverted = true;
|
||||
#elif defined(ESP8266)
|
||||
gpioConfig.hanPin = 3;
|
||||
gpioConfig.ledPin = 2;
|
||||
gpioConfig.ledInverted = true;
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
gpioConfig.hanPin = 18;
|
||||
#elif defined(ESP32)
|
||||
gpioConfig.hanPin = 16;
|
||||
gpioConfig.ledPin = 2;
|
||||
gpioConfig.ledInverted = true;
|
||||
gpioConfig.tempSensorPin = 14;
|
||||
#endif
|
||||
config.clearGpio(gpioConfig);
|
||||
}
|
||||
|
||||
delay(1);
|
||||
@@ -253,7 +218,7 @@ void setup() {
|
||||
debugI("Voltage: %.2fV", vcc);
|
||||
}
|
||||
|
||||
float vccBootLimit = gpioConfig.vccBootLimit == 0 ? 0 : gpioConfig.vccBootLimit / 10.0;
|
||||
float vccBootLimit = gpioConfig.vccBootLimit == 0 ? 0 : min(3.29, gpioConfig.vccBootLimit / 10.0); // Make sure it is never above 3.3v
|
||||
if(vccBootLimit > 2.5 && vccBootLimit < 3.3 && (gpioConfig.apPin == 0xFF || digitalRead(gpioConfig.apPin) == HIGH)) { // Skip if user is holding AP button while booting (HIGH = button is released)
|
||||
if (vcc < vccBootLimit) {
|
||||
if(Debug.isActive(RemoteDebug::INFO)) {
|
||||
@@ -614,15 +579,16 @@ void loop() {
|
||||
if(readHanPort() || now - meterState.getLastUpdateMillis() > 30000) {
|
||||
if(now - lastTemperatureRead > 15000) {
|
||||
unsigned long start = millis();
|
||||
hw.updateTemperatures();
|
||||
lastTemperatureRead = now;
|
||||
if(hw.updateTemperatures()) {
|
||||
lastTemperatureRead = now;
|
||||
|
||||
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
|
||||
mqttHandler->publishTemperatures(&config, &hw);
|
||||
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
|
||||
mqttHandler->publishTemperatures(&config, &hw);
|
||||
}
|
||||
debugD("Used %ld ms to update temperature", millis()-start);
|
||||
}
|
||||
debugD("Used %ld ms to update temperature", millis()-start);
|
||||
}
|
||||
if(now - lastSysupdate > 10000) {
|
||||
if(now - lastSysupdate > 60000) {
|
||||
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
|
||||
mqttHandler->publishSystem(&hw, eapi, &ea);
|
||||
}
|
||||
@@ -634,8 +600,8 @@ void loop() {
|
||||
meterState.setLastError(98);
|
||||
}
|
||||
try {
|
||||
if(meterState.getLastError() > 0) {
|
||||
if(now - meterAutodetectLastChange > 15000 && (meterConfig.baud == 0 || meterConfig.parity == 0)) {
|
||||
if(meterState.getListType() == 0) {
|
||||
if(now - meterAutodetectLastChange > 20000 && (meterConfig.baud == 0 || meterConfig.parity == 0)) {
|
||||
meterAutodetect = true;
|
||||
meterAutoIndex++; // Default is to try the first one in setup()
|
||||
debugI("Meter serial autodetect, swapping to: %d, %d, %s", bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false");
|
||||
@@ -644,7 +610,6 @@ void loop() {
|
||||
meterAutodetectLastChange = now;
|
||||
}
|
||||
} else if(meterAutodetect) {
|
||||
meterAutoIndex--; // Last one worked, so lets use that
|
||||
debugI("Meter serial autodetected, saving: %d, %d, %s", bauds[meterAutoIndex], parities[meterAutoIndex], inverts[meterAutoIndex] ? "true" : "false");
|
||||
meterAutodetect = false;
|
||||
meterConfig.baud = bauds[meterAutoIndex];
|
||||
@@ -899,9 +864,9 @@ bool readHanPort() {
|
||||
pos = unwrapData((uint8_t *) hanBuffer, ctx);
|
||||
if(ctx.type > 0 && pos >= 0) {
|
||||
if(ctx.type == DATA_TAG_DLMS) {
|
||||
debugV("Received valid DLMS at %d", pos);
|
||||
debugD("Received valid DLMS at %d", pos);
|
||||
} else if(ctx.type == DATA_TAG_DSMR) {
|
||||
debugV("Received valid DSMR at %d", pos);
|
||||
debugD("Received valid DSMR at %d", pos);
|
||||
} else {
|
||||
// TODO: Move this so that payload is sent to MQTT
|
||||
debugE("Unknown tag %02X at pos %d", ctx.type, pos);
|
||||
@@ -916,7 +881,7 @@ bool readHanPort() {
|
||||
meterState.setLastError(pos);
|
||||
debugV("Unknown data payload:");
|
||||
len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
|
||||
debugPrint(hanBuffer, 0, len);
|
||||
if(Debug.isActive(RemoteDebug::VERBOSE)) debugPrint(hanBuffer, 0, len);
|
||||
len = 0;
|
||||
return false;
|
||||
}
|
||||
@@ -999,7 +964,7 @@ bool readHanPort() {
|
||||
|
||||
bool saveData = false;
|
||||
if(!ds.isHappy() && now > BUILD_EPOCH) {
|
||||
debugV("Its time to update data storage");
|
||||
debugD("Its time to update data storage");
|
||||
tmElements_t tm;
|
||||
breakTime(now, tm);
|
||||
if(tm.Minute == 0) {
|
||||
@@ -1484,7 +1449,7 @@ void MQTT_connect() {
|
||||
if (strlen(mqttConfig.subscribeTopic) > 0) {
|
||||
mqtt->onMessage(mqttMessageReceived);
|
||||
mqtt->subscribe(String(mqttConfig.subscribeTopic) + "/#");
|
||||
debugI(" Subscribing to [%s]\r\n", mqttConfig.subscribeTopic);
|
||||
debugI(" Subscribing to [%s]\n", mqttConfig.subscribeTopic);
|
||||
}
|
||||
} else {
|
||||
if (Debug.isActive(RemoteDebug::ERROR)) {
|
||||
|
||||