Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ccd2d007 | ||
|
|
bb2f74d1ca | ||
|
|
dfef18fa09 | ||
|
|
485c21dc69 | ||
|
|
9ceb84bc9c | ||
|
|
24e68428c4 | ||
|
|
c2c5855e6a | ||
|
|
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,
|
||||
|
||||
@@ -284,7 +284,7 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
breakTime(tz->toUTC(e2), d2);
|
||||
|
||||
snprintf(buf, BufferSize, "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s",
|
||||
"https://transparency.entsoe.eu/api", getToken(),
|
||||
"https://web-api.tp.entsoe.eu/api", getToken(),
|
||||
d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00,
|
||||
d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00,
|
||||
config->area, config->area);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -119,68 +119,96 @@ void HwTools::getAdcChannel(uint8_t pin, AdcConfig& config) {
|
||||
config.unit = ADC_UNIT_1;
|
||||
config.channel = ADC1_CHANNEL_4;
|
||||
break;
|
||||
#if defined(ADC1_CHANNEL_5)
|
||||
case ADC1_CHANNEL_5_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_1;
|
||||
config.channel = ADC1_CHANNEL_5;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC1_CHANNEL_6)
|
||||
case ADC1_CHANNEL_6_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_1;
|
||||
config.channel = ADC1_CHANNEL_6;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC1_CHANNEL_7)
|
||||
case ADC1_CHANNEL_7_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_1;
|
||||
config.channel = ADC1_CHANNEL_7;
|
||||
break;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#endif
|
||||
#if defined(ADC1_CHANNEL_8)
|
||||
case ADC1_CHANNEL_8_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_1;
|
||||
config.channel = ADC1_CHANNEL_8;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC1_CHANNEL_9)
|
||||
case ADC1_CHANNEL_9_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_1;
|
||||
config.channel = ADC1_CHANNEL_9;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_0)
|
||||
case ADC2_CHANNEL_0_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_0;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_1)
|
||||
case ADC2_CHANNEL_1_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_1;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_2)
|
||||
case ADC2_CHANNEL_2_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_2;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_3)
|
||||
case ADC2_CHANNEL_3_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_3;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_4)
|
||||
case ADC2_CHANNEL_4_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_4;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_5)
|
||||
case ADC2_CHANNEL_5_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_5;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_6)
|
||||
case ADC2_CHANNEL_6_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_6;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_7)
|
||||
case ADC2_CHANNEL_7_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_7;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_8)
|
||||
case ADC2_CHANNEL_8_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_8;
|
||||
break;
|
||||
#endif
|
||||
#if defined(ADC2_CHANNEL_9)
|
||||
case ADC2_CHANNEL_9_GPIO_NUM:
|
||||
config.unit = ADC_UNIT_2;
|
||||
config.channel = ADC2_CHANNEL_9;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
2
lib/SvelteUi/app/.gitignore
vendored
@@ -8,8 +8,6 @@ pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
|
||||
19
lib/SvelteUi/app/dist/favicon.svg
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
|
||||
<title>Amsleser</title>
|
||||
<g transform="translate(-29.5,-83)">
|
||||
<circle r="4.8016944" cy="123.56455" cx="55.064552"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path d="m 41.298717,103.9049 a 24,24 0 0 1 27.531669,0"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3.3;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path d="m 35.562952,95.713384 a 34,34 0 0 1 39.003199,-2e-6"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3.3;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path d="m 47.034482,112.09642 a 14,14 0 0 1 16.06014,0"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:3.3;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle r="3" cy="105.99158" cx="38.181862"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle r="3" cy="97.959579" cx="77.491386"
|
||||
style="fill:none;stroke:#045c7c;stroke-width:2.4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
6
lib/SvelteUi/app/dist/github.svg
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 499.36" focusable="false">
|
||||
<title>GitHub</title>
|
||||
<path d="M256 0C114.64 0 0 114.61 0 256c0 113.09 73.34 209 175.08 242.9 12.8 2.35 17.47-5.56 17.47-12.34 0-6.08-.22-22.18-.35-43.54-71.2 15.49-86.2-34.34-86.2-34.34-11.64-29.57-28.42-37.45-28.42-37.45-23.27-15.84 1.73-15.55 1.73-15.55 25.69 1.81 39.21 26.38 39.21 26.38 22.84 39.12 59.92 27.82 74.5 21.27 2.33-16.54 8.94-27.82 16.25-34.22-56.84-6.43-116.6-28.43-116.6-126.49 0-27.95 10-50.8 26.35-68.69-2.63-6.48-11.42-32.5 2.51-67.75 0 0 21.49-6.88 70.4 26.24a242.65 242.65 0 0 1 128.18 0c48.87-33.13 70.33-26.24 70.33-26.24 14 35.25 5.18 61.27 2.55 67.75 16.41 17.9 26.31 40.75 26.31 68.69 0 98.35-59.85 120-116.88 126.32 9.19 7.9 17.38 23.53 17.38 47.41 0 34.22-.31 61.83-.31 70.23 0 6.85 4.61 14.81 17.6 12.31C438.72 464.97 512 369.08 512 256.02 512 114.62 397.37 0 256 0z" fill="#f8f9fa" fill-rule="evenodd"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
lib/SvelteUi/app/dist/index.css
vendored
Normal file
16
lib/SvelteUi/app/dist/index.html
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href="/favicon.svg">
|
||||
<link rel="mask-icon" href="/favicon.svg" color="#000000">
|
||||
<title>AMS reader</title>
|
||||
<script type="module" crossorigin src="/index.js"></script>
|
||||
<link rel="stylesheet" href="/index.css">
|
||||
</head>
|
||||
<body class="bg-gray-100">
|
||||
<div id="app"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
13
lib/SvelteUi/app/dist/index.js
vendored
Normal file
@@ -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>
|
||||
|
||||
@@ -11,6 +11,10 @@
|
||||
@apply bg-white m-2 p-2 rounded shadow-lg
|
||||
}
|
||||
|
||||
.gwf {
|
||||
@apply 2xl:col-span-6 xl:col-span-5 lg:col-span-4 md:col-span-3 sm:col-span-2 h-64
|
||||
}
|
||||
|
||||
.in-pre {
|
||||
@apply flex items-center bg-gray-100 rounded-l-md border border-r-0 border-gray-300 px-3 whitespace-nowrap text-sm
|
||||
}
|
||||
@@ -38,25 +42,28 @@
|
||||
@apply text-right
|
||||
}
|
||||
|
||||
.bd-grn {
|
||||
.bd-green {
|
||||
@apply my-auto bg-green-500 text-green-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-ylo {
|
||||
.bd-yellow {
|
||||
@apply my-auto bg-yellow-500 text-yellow-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-red {
|
||||
@apply my-auto bg-red-500 text-red-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-blu {
|
||||
.bd-blue {
|
||||
@apply my-auto bg-blue-500 text-blue-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
.bd-gry {
|
||||
.bd-gray {
|
||||
@apply my-auto bg-gray-500 text-gray-100 text-xs font-semibold mr-2 px-2.5 py-0.5 rounded
|
||||
}
|
||||
|
||||
.btn-pri {
|
||||
@apply py-2 px-4 rounded bg-blue-500 text-white mr-3
|
||||
}
|
||||
.btn-pri-sm {
|
||||
@apply text-xs py-1 px-2 rounded bg-blue-500 text-white mr-3
|
||||
}
|
||||
|
||||
.pl-root {
|
||||
position: relative;
|
||||
|
||||
@@ -1,54 +1,68 @@
|
||||
<script>
|
||||
import { fmtnum } from "./Helpers";
|
||||
|
||||
|
||||
export let data;
|
||||
export let currency;
|
||||
export let hasExport;
|
||||
|
||||
let hasExport = data && (data.om || data.e > 0);
|
||||
let cols = 3
|
||||
$: {
|
||||
cols = currency ? 3 : 2;
|
||||
}
|
||||
</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">
|
||||
<br/><br/>
|
||||
|
||||
{#if data}
|
||||
{#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>
|
||||
<strong>Import</strong>
|
||||
<div class="grid grid-cols-{cols} mb-3">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{fmtnum(data.h.u,2)} kWh</div>
|
||||
{#if currency}<div class="text-right">{fmtnum(data.h.c,2)} {currency}</div>{/if}
|
||||
<div>Day</div>
|
||||
<div class="text-right">{fmtnum(data.d.u,1)} kWh</div>
|
||||
{#if currency}<div class="text-right">{fmtnum(data.d.c,1)} {currency}</div>{/if}
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.u)} kWh</div>
|
||||
{#if currency}<div class="text-right">{fmtnum(data.m.c)} {currency}</div>{/if}
|
||||
</div>
|
||||
<strong>Export</strong>
|
||||
<div class="grid grid-cols-{cols}">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{fmtnum(data.h.p,2)} kWh</div>
|
||||
{#if currency}<div class="text-right">{fmtnum(data.h.i,2)} {currency}</div>{/if}
|
||||
<div>Day</div>
|
||||
<div class="text-right">{fmtnum(data.d.p,1)} kWh</div>
|
||||
{#if currency}<div class="text-right">{fmtnum(data.d.i,1)} {currency}</div>{/if}
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.p)} kWh</div>
|
||||
{#if currency}<div class="text-right">{fmtnum(data.m.i)} {currency}</div>{/if}
|
||||
</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">{fmtnum(data.h.u,2)} kWh</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{fmtnum(data.d.u,1)} kWh</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.u)} kWh</div>
|
||||
</div>
|
||||
{#if currency}
|
||||
<strong>Cost</strong>
|
||||
<div class="grid grid-cols-2">
|
||||
<div>Hour</div>
|
||||
<div class="text-right">{fmtnum(data.h.c,2)} {currency}</div>
|
||||
<div>Day</div>
|
||||
<div class="text-right">{fmtnum(data.d.c,1)} {currency}</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.c)} {currency}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import BarChart from './BarChart.svelte';
|
||||
import { ampcol } from './Helpers.js';
|
||||
import { ampcol, fmtnum } from './Helpers.js';
|
||||
|
||||
export let u1;
|
||||
export let u2;
|
||||
@@ -12,32 +12,28 @@
|
||||
|
||||
let config = {};
|
||||
|
||||
function point(v) {
|
||||
return {
|
||||
label: fmtnum(v) +'A',
|
||||
value: isNaN(v) ? 0 : v,
|
||||
color: ampcol(v ? (v)/(max)*100 : 0)
|
||||
};
|
||||
};
|
||||
|
||||
$: {
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
if(u1 > 0) {
|
||||
xTicks.push({ label: 'L1' });
|
||||
points.push({
|
||||
label: i1 ? (i1 > 10 ? i1.toFixed(0) : i1.toFixed(1)) + 'A' : '-',
|
||||
value: i1 ? i1 : 0,
|
||||
color: ampcol(i1 ? (i1)/(max)*100 : 0)
|
||||
});
|
||||
points.push(point(i1));
|
||||
}
|
||||
if(u2 > 0) {
|
||||
xTicks.push({ label: 'L2' });
|
||||
points.push({
|
||||
label: i2 ? (i2 > 10 ? i2.toFixed(0) : i2.toFixed(1)) + 'A' : '-',
|
||||
value: i2 ? i2 : 0,
|
||||
color: ampcol(i2 ? (i2)/(max)*100 : 0)
|
||||
});
|
||||
points.push(point(i2));
|
||||
}
|
||||
if(u3 > 0) {
|
||||
xTicks.push({ label: 'L3' });
|
||||
points.push({
|
||||
label: i3 ? (i3 > 10 ? i3.toFixed(0) : i3.toFixed(1)) + 'A' : '-',
|
||||
value: i3 ? i3 : 0,
|
||||
color: ampcol(i3 ? (i3)/(max)*100 : 0)
|
||||
});
|
||||
points.push(point(i3));
|
||||
}
|
||||
config = {
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
|
||||
@@ -3,14 +3,4 @@
|
||||
export let title;
|
||||
export let text;
|
||||
</script>
|
||||
{#if color == 'green'}
|
||||
<span title={title} class="bd-grn">{text}</span>
|
||||
{:else if color === `yellow`}
|
||||
<span title={title} class="bd-ylo">{text}</span>
|
||||
{:else if color === `red`}
|
||||
<span title={title} class="bd-red">{text}</span>
|
||||
{:else if color === `blue`}
|
||||
<span title={title} class="bd-blu">{text}</span>
|
||||
{:else if color === `gray`}
|
||||
<span title={title} class="bd-gry">{text}</span>
|
||||
{/if}
|
||||
<span title={title} class="bd-{color}">{text}</span>
|
||||
|
||||
@@ -1,16 +1,53 @@
|
||||
<script>
|
||||
import { getConfiguration, configurationStore } from './ConfigurationStore'
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import { wiki } from './Helpers.js';
|
||||
import UartSelectOptions from './UartSelectOptions.svelte';
|
||||
import Mask from './Mask.svelte'
|
||||
import Badge from './Badge.svelte';
|
||||
import HelpIcon from './HelpIcon.svelte';
|
||||
import CountrySelectOptions from './CountrySelectOptions.svelte';
|
||||
import { Link, navigate } from 'svelte-navigator';
|
||||
import SubnetOptions from './SubnetOptions.svelte';
|
||||
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
let uiElements = [{
|
||||
name: 'Import gauge',
|
||||
key: 'i'
|
||||
},{
|
||||
name: 'Export gauge',
|
||||
key: 'e'
|
||||
},{
|
||||
name: 'Voltage',
|
||||
key: 'v'
|
||||
},{
|
||||
name: 'Amperage',
|
||||
key: 'a'
|
||||
},{
|
||||
name: 'Reactive',
|
||||
key: 'r'
|
||||
},{
|
||||
name: 'Realtime',
|
||||
key: 'c'
|
||||
},{
|
||||
name: 'Peaks',
|
||||
key: 't'
|
||||
},{
|
||||
name: 'Price',
|
||||
key: 'p'
|
||||
},{
|
||||
name: 'Day plot',
|
||||
key: 'd'
|
||||
},{
|
||||
name: 'Month plot',
|
||||
key: 'm'
|
||||
},{
|
||||
name: 'Temperature plot',
|
||||
key: 's'
|
||||
}];
|
||||
|
||||
let loading = true;
|
||||
let saving = false;
|
||||
|
||||
@@ -67,8 +104,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 +115,8 @@
|
||||
body: data
|
||||
});
|
||||
let res = (await response.json());
|
||||
isFactoryReset = res.success;
|
||||
isFactoryReset = false;
|
||||
isFactoryResetComplete = res.success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,22 +169,28 @@
|
||||
if(configuration.q.p == 8883) configuration.q.p = 1883;
|
||||
}
|
||||
}
|
||||
|
||||
let gpioMax = 44;
|
||||
$: {
|
||||
gpioMax = sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<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="{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/>
|
||||
<select name="gt" bind:value={configuration.g.t} class="in-l">
|
||||
<select name="gt" bind:value={configuration.g.t} class="in-l w-full">
|
||||
<CountrySelectOptions/>
|
||||
</select>
|
||||
</div>
|
||||
@@ -191,10 +237,9 @@
|
||||
<div class="w-1/2">
|
||||
Currency<br/>
|
||||
<select name="pc" bind:value={configuration.p.c} class="in-f w-full">
|
||||
<option value="NOK">NOK</option>
|
||||
<option value="SEK">SEK</option>
|
||||
<option value="DKK">DKK</option>
|
||||
<option value="EUR">EUR</option>
|
||||
{#each ["NOK","SEK","DKK","EUR"] as c}
|
||||
<option value={c}>{c}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
@@ -230,20 +275,16 @@
|
||||
</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="{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>
|
||||
<div class="flex">
|
||||
<select name="mb" bind:value={configuration.m.b} class="in-f">
|
||||
<option value={0} disabled={configuration.m.b != 0}>Autodetect</option>
|
||||
<option value={2400}>2400</option>
|
||||
<option value={4800}>4800</option>
|
||||
<option value={9600}>9600</option>
|
||||
<option value={19200}>19200</option>
|
||||
<option value={38400}>38400</option>
|
||||
<option value={57600}>57600</option>
|
||||
<option value={115200}>115200</option>
|
||||
{#each [24,48,96,192,384,576,1152] as b}
|
||||
<option value={b*100}>{b*100}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<select name="mp" bind:value={configuration.m.p} class="in-l" disabled={configuration.m.b == 0}>
|
||||
<option value={0} disabled={configuration.m.b != 0}>-</option>
|
||||
@@ -259,9 +300,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 +360,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="{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 +394,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="{wiki('Network-configuration')}" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<div class="my-1">
|
||||
IP<br/>
|
||||
<div class="flex">
|
||||
@@ -362,11 +402,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 +434,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="{wiki('MQTT-configuration')}" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="q" value="true"/>
|
||||
<div class="my-1">
|
||||
Server
|
||||
@@ -471,7 +509,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="{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 +526,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,54 +534,16 @@
|
||||
{#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="{wiki('Threshold-configuration')}" target="_blank" class="float-right"><HelpIcon/></a>
|
||||
<input type="hidden" name="t" value="true"/>
|
||||
<div class="flex flex-wrap my-1">
|
||||
{#each {length: 9} as _, i}
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">1</span>
|
||||
<input name="t0" bind:value={configuration.t.t[0]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">2</span>
|
||||
<input name="t1" bind:value={configuration.t.t[1]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">3</span>
|
||||
<input name="t2" bind:value={configuration.t.t[2]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">4</span>
|
||||
<input name="t3" bind:value={configuration.t.t[3]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">5</span>
|
||||
<input name="t4" bind:value={configuration.t.t[4]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">6</span>
|
||||
<input name="t5" bind:value={configuration.t.t[5]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">7</span>
|
||||
<input name="t6" bind:value={configuration.t.t[6]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">8</span>
|
||||
<input name="t7" bind:value={configuration.t.t[7]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
<label class="flex w-40 m-1">
|
||||
<span class="in-pre">9</span>
|
||||
<input name="t8" bind:value={configuration.t.t[8]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-pre">{i+1}</span>
|
||||
<input name="t{i}" bind:value={configuration.t.t[i]} type="number" min="0" max="255" class="in-txt w-full"/>
|
||||
<span class="in-post">kWh</span>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
<label class="flex m-1">
|
||||
<span class="in-pre">Average of</span>
|
||||
@@ -554,102 +554,25 @@
|
||||
{/if}
|
||||
<div class="cnt">
|
||||
<strong class="text-sm">User interface</strong>
|
||||
<a href="{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">
|
||||
Import gauge<br/>
|
||||
<select name="ui" bind:value={configuration.u.i} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Export gauge<br/>
|
||||
<select name="ue" bind:value={configuration.u.e} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Voltage<br/>
|
||||
<select name="uv" bind:value={configuration.u.v} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Amperage<br/>
|
||||
<select name="ua" bind:value={configuration.u.a} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Reactive<br/>
|
||||
<select name="ur" bind:value={configuration.u.r} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Realtime<br/>
|
||||
<select name="uc" bind:value={configuration.u.c} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Peaks<br/>
|
||||
<select name="ut" bind:value={configuration.u.t} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Price<br/>
|
||||
<select name="up" bind:value={configuration.u.p} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Day plot<br/>
|
||||
<select name="ud" bind:value={configuration.u.d} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Month plot<br/>
|
||||
<select name="um" bind:value={configuration.u.m} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
Temperature plot<br/>
|
||||
<select name="us" bind:value={configuration.u.s} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
{#each uiElements as el}
|
||||
<div class="w-1/2">
|
||||
{el.name}<br/>
|
||||
<select name="u{el.key}" bind:value={configuration.u[el.key]} class="in-s">
|
||||
<option value={0}>Hide</option>
|
||||
<option value={1}>Show</option>
|
||||
<option value={2}>Dynamic</option>
|
||||
</select>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{#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="{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">
|
||||
@@ -661,34 +584,34 @@
|
||||
</div>
|
||||
<div class="w-1/3">
|
||||
AP button<br/>
|
||||
<input name="ia" bind:value={configuration.i.a} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-m tr w-full"/>
|
||||
<input name="ia" bind:value={configuration.i.a} type="number" min="0" max={gpioMax} class="in-m tr w-full"/>
|
||||
</div>
|
||||
<div class="w-1/3">
|
||||
LED<label class="ml-4"><input name="ili" value="true" bind:checked={configuration.i.l.i} type="checkbox" class="rounded mb-1"/> inv</label><br/>
|
||||
<div class="flex">
|
||||
<input name="ilp" bind:value={configuration.i.l.p} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-l tr w-full"/>
|
||||
<input name="ilp" bind:value={configuration.i.l.p} type="number" min="0" max={gpioMax} class="in-l tr w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
RGB<label class="ml-4"><input name="iri" value="true" bind:checked={configuration.i.r.i} type="checkbox" class="rounded mb-1"/> inverted</label><br/>
|
||||
<div class="flex">
|
||||
<input name="irr" bind:value={configuration.i.r.r} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-f tr w-1/3"/>
|
||||
<input name="irg" bind:value={configuration.i.r.g} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-m tr w-1/3"/>
|
||||
<input name="irb" bind:value={configuration.i.r.b} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-l tr w-1/3"/>
|
||||
<input name="irr" bind:value={configuration.i.r.r} type="number" min="0" max={gpioMax} class="in-f tr w-1/3"/>
|
||||
<input name="irg" bind:value={configuration.i.r.g} type="number" min="0" max={gpioMax} class="in-m tr w-1/3"/>
|
||||
<input name="irb" bind:value={configuration.i.r.b} type="number" min="0" max={gpioMax} class="in-l tr w-1/3"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="my-1 w-1/3">
|
||||
Temperature<br/>
|
||||
<input name="itd" bind:value={configuration.i.t.d} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-f tr w-full"/>
|
||||
<input name="itd" bind:value={configuration.i.t.d} type="number" min="0" max={gpioMax} class="in-f tr w-full"/>
|
||||
</div>
|
||||
<div class="my-1 pr-1 w-1/3">
|
||||
Analog temp<br/>
|
||||
<input name="ita" bind:value={configuration.i.t.a} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-l tr w-full"/>
|
||||
<input name="ita" bind:value={configuration.i.t.a} type="number" min="0" max={gpioMax} class="in-l tr w-full"/>
|
||||
</div>
|
||||
{#if sysinfo.chip != 'esp8266'}
|
||||
<div class="my-1 pl-1 w-1/3">
|
||||
Vcc<br/>
|
||||
<input name="ivp" bind:value={configuration.i.v.p} type="number" min="0" max={sysinfo.chip == 'esp8266' ? 16 : sysinfo.chip == 'esp32s2' ? 44 : 39} class="in-s tr w-full"/>
|
||||
<input name="ivp" bind:value={configuration.i.v.p} type="number" min="0" max={gpioMax} class="in-s tr w-full"/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if configuration.i.v.p > 0}
|
||||
@@ -764,4 +687,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"/>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { sysinfoStore } from './DataStores.js';
|
||||
import Mask from './Mask.svelte'
|
||||
import { navigate } from 'svelte-navigator';
|
||||
import { wiki } from './Helpers';
|
||||
|
||||
export let sysinfo = {}
|
||||
|
||||
@@ -41,7 +42,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="{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 gwf">
|
||||
<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 gwf">
|
||||
<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 gwf">
|
||||
<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 gwf">
|
||||
<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);
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script>
|
||||
import { Link } from "svelte-navigator";
|
||||
import { sysinfoStore, getGitHubReleases, gitHubReleaseStore } from './DataStores.js';
|
||||
import { upgrade, getNextVersion } from './UpgradeHelper';
|
||||
import { boardtype, hanError, mqttError, priceError, isBusPowered } from './Helpers.js';
|
||||
import { upgrade, getNextVersion, upgradeWarningText } from './UpgradeHelper';
|
||||
import { boardtype, hanError, mqttError, priceError, isBusPowered, wiki, bcol } from './Helpers.js';
|
||||
import AmsleserSvg from "./../assets/favicon.svg";
|
||||
import GitHubLogo from './../assets/github.svg';
|
||||
import Uptime from "./Uptime.svelte";
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
function askUpgrade() {
|
||||
if(confirm('Do you want to upgrade this device to ' + nextVersion.tag_name + '?')) {
|
||||
if(!isBusPowered(sysinfo.board) || confirm('WARNING: ' + boardtype(sysinfo.chip, sysinfo.board) + ' must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.')) {
|
||||
if(!isBusPowered(sysinfo.board) || confirm(upgradeWarningText(boardtype(sysinfo.chip, sysinfo.board)))) {
|
||||
sysinfoStore.update(s => {
|
||||
s.upgrading = true;
|
||||
return s;
|
||||
@@ -54,10 +54,10 @@
|
||||
<div class="flex-none my-auto">Free mem: {data.m ? (data.m/1000).toFixed(1) : '-'}kb</div>
|
||||
</div>
|
||||
<div class="flex-auto flex-wrap my-auto justify-center p-2">
|
||||
<Badge title="ESP" text={sysinfo.booting ? 'Booting' : data.v > 2.0 ? data.v.toFixed(2)+"V" : "ESP"} color={sysinfo.booting ? 'yellow' : data.em === 1 ? 'green' : data.em === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="HAN" text="HAN" color={sysinfo.booting ? 'gray' : data.hm === 1 ? 'green' : data.hm === 2 ? 'yellow' : data.hm === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="WiFi" text={data.r ? data.r.toFixed(0)+"dBm" : "WiFi"} color={sysinfo.booting ? 'gray' : data.wm === 1 ? 'green' : data.wm === 2 ? 'yellow' : data.wm === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="MQTT" text="MQTT" color={sysinfo.booting ? 'gray' : data.mm === 1 ? 'green' : data.mm === 2 ? 'yellow' : data.mm === 3 ? 'red' : 'gray'}/>
|
||||
<Badge title="ESP" text={sysinfo.booting ? 'Booting' : data.v > 2.0 ? data.v.toFixed(2)+"V" : "ESP"} color={bcol(sysinfo.booting ? 2 : data.em)}/>
|
||||
<Badge title="HAN" text="HAN" color={bcol(sysinfo.booting ? 9 : data.hm)}/>
|
||||
<Badge title="WiFi" text={data.r ? data.r.toFixed(0)+"dBm" : "WiFi"} color={bcol(sysinfo.booting ? 9 : data.wm)}/>
|
||||
<Badge title="MQTT" text="MQTT" color={bcol(sysinfo.booting ? 9 : data.mm)}/>
|
||||
</div>
|
||||
{#if data.he < 0 || data.he > 0}
|
||||
<div class="bd-red">{ 'HAN: ' + hanError(data.he) }</div>
|
||||
@@ -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={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,14 @@
|
||||
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 bcol(num) {
|
||||
return num === 1 ? 'green' : num === 2 ? 'yellow' : num === 3 ? 'red' : 'gray';
|
||||
}
|
||||
|
||||
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 +19,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:
|
||||
@@ -158,3 +164,14 @@ export function isBusPowered(boardType) {
|
||||
export function uiVisibility(choice, state) {
|
||||
return choice == 1 || (choice == 2 && state);
|
||||
}
|
||||
|
||||
export function wiki(page) {
|
||||
return "https://github.com/UtilitechAS/amsreader-firmware/wiki/" + page;
|
||||
}
|
||||
|
||||
export function fmtnum(v,d) {
|
||||
if(isNaN(v)) return '-';
|
||||
if(isNaN(d))
|
||||
d = v < 10 ? 1 : 0;
|
||||
return v.toFixed(d);
|
||||
}
|
||||
@@ -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/>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
export let exportTotal;
|
||||
</script>
|
||||
|
||||
<div class="mx-2">
|
||||
<strong class="text-sm">Reactive</strong>
|
||||
<div class="mx-2 text-sm">
|
||||
<strong>Reactive</strong>
|
||||
|
||||
<div class="grid grid-cols-2 mt-4">
|
||||
<div>Instant in</div>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1,13 +1,42 @@
|
||||
<script>
|
||||
import { metertype, boardtype, isBusPowered } from './Helpers.js';
|
||||
import { getSysinfo, gitHubReleaseStore, sysinfoStore } from './DataStores.js';
|
||||
import { upgrade, getNextVersion } from './UpgradeHelper';
|
||||
import { upgrade, getNextVersion, upgradeWarningText } from './UpgradeHelper';
|
||||
import DownloadIcon from './DownloadIcon.svelte';
|
||||
import { Link } from 'svelte-navigator';
|
||||
import Mask from './Mask.svelte';
|
||||
|
||||
export let data;
|
||||
export let sysinfo;
|
||||
|
||||
let cfgItems = [{
|
||||
name: 'WiFi',
|
||||
key: 'iw'
|
||||
},{
|
||||
name: 'MQTT',
|
||||
key: 'im'
|
||||
},{
|
||||
name: 'Web',
|
||||
key: 'ie'
|
||||
},{
|
||||
name: 'Meter',
|
||||
key: 'it'
|
||||
},{
|
||||
name: 'Thresholds',
|
||||
key: 'ih'
|
||||
},{
|
||||
name: 'GPIO',
|
||||
key: 'ig'
|
||||
},{
|
||||
name: 'Domoticz',
|
||||
key: 'id'
|
||||
},{
|
||||
name: 'NTP',
|
||||
key: 'in'
|
||||
},{
|
||||
name: 'Price API',
|
||||
key: 'is'
|
||||
}];
|
||||
|
||||
let nextVersion = {};
|
||||
gitHubReleaseStore.subscribe(releases => {
|
||||
@@ -19,7 +48,7 @@
|
||||
|
||||
function askUpgrade() {
|
||||
if(confirm('Do you want to upgrade this device to ' + nextVersion.tag_name + '?')) {
|
||||
if((sysinfo.board != 2 && sysinfo.board != 4 && sysinfo.board != 7) || confirm('WARNING: ' + boardtype(sysinfo.chip, sysinfo.board) + ' must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.')) {
|
||||
if((sysinfo.board != 2 && sysinfo.board != 4 && sysinfo.board != 7) || confirm(upgradeWarningText(boardtype(sysinfo.chip, sysinfo.board)))) {
|
||||
sysinfoStore.update(s => {
|
||||
s.upgrading = true;
|
||||
return s;
|
||||
@@ -64,7 +93,7 @@
|
||||
Chip: {sysinfo.chip}
|
||||
</div>
|
||||
<div class="my-2">
|
||||
Device: {boardtype(sysinfo.chip, sysinfo.board)}
|
||||
Device: <Link to="/vendor">{boardtype(sysinfo.chip, sysinfo.board)}</Link>
|
||||
</div>
|
||||
<div class="my-2">
|
||||
MAC: {sysinfo.mac}
|
||||
@@ -76,7 +105,7 @@
|
||||
{/if}
|
||||
<div class="my-2">
|
||||
<Link to="/consent">
|
||||
<span class="text-xs py-1 px-2 rounded bg-blue-500 text-white mr-3 ">Update consents</span>
|
||||
<span class="btn-pri-sm">Update consents</span>
|
||||
</Link>
|
||||
<button on:click={askReboot} class="text-xs py-1 px-2 rounded bg-yellow-500 text-white mr-3 float-right">Reboot</button>
|
||||
</div>
|
||||
@@ -129,13 +158,13 @@
|
||||
</div>
|
||||
{#if sysinfo.fwconsent === 2}
|
||||
<div class="my-2">
|
||||
<div class="bd-ylo">You have disabled one-click firmware upgrade, link to self-upgrade is disabled</div>
|
||||
<div class="bd-yellow">You have disabled one-click firmware upgrade, link to self-upgrade is disabled</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if (sysinfo.security == 0 || data.a) && isBusPowered(sysinfo.board) }
|
||||
<div class="bd-red">
|
||||
{boardtype(sysinfo.chip, sysinfo.board)} must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.
|
||||
{upgradeWarningText(boardtype(sysinfo.chip, sysinfo.board))}
|
||||
</div>
|
||||
{/if}
|
||||
{#if sysinfo.security == 0 || data.a}
|
||||
@@ -143,10 +172,10 @@
|
||||
<form action="/firmware" enctype="multipart/form-data" method="post" on:submit={() => firmwareUploading=true} autocomplete="off">
|
||||
<input style="display:none" name="file" type="file" accept=".bin" bind:this={firmwareFileInput} bind:files={firmwareFiles}>
|
||||
{#if firmwareFiles.length == 0}
|
||||
<button type="button" on:click={()=>{firmwareFileInput.click();}} class="text-xs py-1 px-2 rounded bg-blue-500 text-white float-right mr-3">Select firmware file for upgrade</button>
|
||||
<button type="button" on:click={()=>{firmwareFileInput.click();}} class="btn-pri-sm float-right">Select firmware file for upgrade</button>
|
||||
{:else}
|
||||
{firmwareFiles[0].name}
|
||||
<button type="submit" class="ml-2 text-xs py-1 px-2 rounded bg-blue-500 text-white float-right mr-3">Upload</button>
|
||||
<button type="submit" class="btn-pri-sm float-right">Upload</button>
|
||||
{/if}
|
||||
</form>
|
||||
</div>
|
||||
@@ -157,28 +186,22 @@
|
||||
<strong class="text-sm">Configuration</strong>
|
||||
<form method="get" action="/configfile.cfg" autocomplete="off">
|
||||
<div class="grid grid-cols-2">
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="iw" value="true" checked/> WiFi</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="im" value="true" checked/> MQTT</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="ie" value="true" checked/> Web</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="it" value="true" checked/> Meter</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="ih" value="true" checked/> Thresholds</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="ig" value="true" checked/> GPIO</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="id" value="true" checked/> Domoticz</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="in" value="true" checked/> NTP</label>
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="is" value="true" checked/> Price API</label>
|
||||
{#each cfgItems as el}
|
||||
<label class="my-1 mx-3"><input type="checkbox" class="rounded" name="{el.key}" value="true" checked/> {el.name}</label>
|
||||
{/each}
|
||||
<label class="my-1 mx-3 col-span-2"><input type="checkbox" class="rounded" name="ic" value="true"/> Include Secrets<br/><small>(SSID, PSK, passwords and tokens)</small></label>
|
||||
</div>
|
||||
{#if configFiles.length == 0}
|
||||
<button type="submit" class="ml-2 text-xs py-1 px-2 rounded bg-blue-500 text-white float-right mr-3">Download</button>
|
||||
<button type="submit" class="btn-pri-sm float-right">Download</button>
|
||||
{/if}
|
||||
</form>
|
||||
<form action="/configfile" enctype="multipart/form-data" method="post" on:submit={() => configUploading=true} autocomplete="off">
|
||||
<input style="display:none" name="file" type="file" accept=".cfg" bind:this={configFileInput} bind:files={configFiles}>
|
||||
{#if configFiles.length == 0}
|
||||
<button type="button" on:click={()=>{configFileInput.click();}} class="text-xs py-1 px-2 rounded bg-blue-500 text-white mr-3">Select file...</button>
|
||||
<button type="button" on:click={()=>{configFileInput.click();}} class="btn-pri-sm">Select file...</button>
|
||||
{:else}
|
||||
{configFiles[0].name}
|
||||
<button type="submit" class="ml-2 text-xs py-1 px-2 rounded bg-blue-500 text-white mr-3">Upload</button>
|
||||
<button type="submit" class="btn-pri-sm">Upload</button>
|
||||
{/if}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
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>
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
<script>
|
||||
export let chip;
|
||||
|
||||
let gpioMax = 44;
|
||||
$: {
|
||||
gpioMax = chip == 'esp8266' ? 16 : chip == 'esp32s2' ? 44 : 39;
|
||||
}
|
||||
</script>
|
||||
|
||||
<option value={3}>UART0</option>
|
||||
@@ -13,46 +18,15 @@
|
||||
{#if chip == 'esp32s2'}
|
||||
<option value={18}>UART1</option>
|
||||
{/if}
|
||||
<option value={4}>GPIO4</option>
|
||||
<option value={5}>GPIO5</option>
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={6}>GPIO6</option>
|
||||
<option value={7}>GPIO7</option>
|
||||
<option value={8}>GPIO8</option>
|
||||
{/if}
|
||||
{#if chip == 'esp8266'}
|
||||
<option value={9}>GPIO9</option>
|
||||
{/if}
|
||||
<option value={10}>GPIO10</option>
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={11}>GPIO11</option>
|
||||
{/if}
|
||||
<option value={12}>GPIO12</option>
|
||||
<option value={13}>GPIO13</option>
|
||||
<option value={14}>GPIO14</option>
|
||||
<option value={15}>GPIO15</option>
|
||||
|
||||
{#if chip.startsWith('esp32')}
|
||||
<option value={17}>GPIO17</option>
|
||||
{#if chip != 'esp32s2'}
|
||||
<option value={18}>GPIO18</option>
|
||||
{/if}
|
||||
<option value={19}>GPIO19</option>
|
||||
<option value={21}>GPIO21</option>
|
||||
<option value={22}>GPIO22</option>
|
||||
<option value={23}>GPIO23</option>
|
||||
<option value={25}>GPIO25</option>
|
||||
<option value={32}>GPIO32</option>
|
||||
<option value={33}>GPIO33</option>
|
||||
<option value={34}>GPIO34</option>
|
||||
<option value={35}>GPIO35</option>
|
||||
<option value={36}>GPIO36</option>
|
||||
<option value={39}>GPIO39</option>
|
||||
{/if}
|
||||
{#if chip == 'esp32s2'}
|
||||
<option value={40}>GPIO40</option>
|
||||
<option value={41}>GPIO41</option>
|
||||
<option value={42}>GPIO42</option>
|
||||
<option value={43}>GPIO43</option>
|
||||
<option value={44}>GPIO44</option>
|
||||
{#each {length: gpioMax+1} as _, i}
|
||||
{#if i > 3
|
||||
&& !(chip == 'esp32' && (i == 9 || i == 16))
|
||||
&& !(chip == 'esp32s2' && i == 18)
|
||||
&& !(chip == 'esp8266' && (i == 3 || i == 113))
|
||||
}
|
||||
<option value={i}>GPIO{i}</option>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
@@ -1,31 +1,33 @@
|
||||
export async function upgrade(version) {
|
||||
const data = new URLSearchParams()
|
||||
data.append('version', version.tag_name);
|
||||
export function upgradeWarningText(board) {
|
||||
return 'WARNING: ' + board + ' must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.'
|
||||
}
|
||||
|
||||
export async function upgrade() {
|
||||
const response = await fetch('/upgrade', {
|
||||
method: 'POST',
|
||||
body: data
|
||||
method: 'POST'
|
||||
});
|
||||
let res = (await response.json())
|
||||
await response.json();
|
||||
}
|
||||
|
||||
export function getNextVersion(currentVersion, releases) {
|
||||
export function getNextVersion(currentVersion, releases_orig) {
|
||||
if(/^v\d{1,2}\.\d{1,2}\.\d{1,2}$/.test(currentVersion)) {
|
||||
var v = currentVersion.substring(1).split('.');
|
||||
var v_major = parseInt(v[0]);
|
||||
var v_minor = parseInt(v[1]);
|
||||
var v_patch = parseInt(v[2]);
|
||||
let v = currentVersion.substring(1).split('.');
|
||||
let v_major = parseInt(v[0]);
|
||||
let v_minor = parseInt(v[1]);
|
||||
let v_patch = parseInt(v[2]);
|
||||
|
||||
let releases = [...releases_orig];
|
||||
releases.reverse();
|
||||
var next_patch;
|
||||
var next_minor;
|
||||
var next_major;
|
||||
for(var i = 0; i < releases.length; i++) {
|
||||
var release = releases[i];
|
||||
var ver2 = release.tag_name;
|
||||
var v2 = ver2.substring(1).split('.');
|
||||
var v2_major = parseInt(v2[0]);
|
||||
var v2_minor = parseInt(v2[1]);
|
||||
var v2_patch = parseInt(v2[2]);
|
||||
let next_patch;
|
||||
let next_minor;
|
||||
let next_major;
|
||||
for(let i = 0; i < releases.length; i++) {
|
||||
let release = releases[i];
|
||||
let ver2 = release.tag_name;
|
||||
let v2 = ver2.substring(1).split('.');
|
||||
let v2_major = parseInt(v2[0]);
|
||||
let v2_minor = parseInt(v2[1]);
|
||||
let v2_patch = parseInt(v2[2]);
|
||||
|
||||
if(v2_major == v_major) {
|
||||
if(v2_minor == v_minor) {
|
||||
@@ -37,10 +39,10 @@ export function getNextVersion(currentVersion, releases) {
|
||||
}
|
||||
} else if(v2_major == v_major+1) {
|
||||
if(next_major) {
|
||||
var mv = next_major.tag_name.substring(1).split('.');
|
||||
var mv_major = parseInt(mv[0]);
|
||||
var mv_minor = parseInt(mv[1]);
|
||||
var mv_patch = parseInt(mv[2]);
|
||||
let mv = next_major.tag_name.substring(1).split('.');
|
||||
let mv_major = parseInt(mv[0]);
|
||||
let mv_minor = parseInt(mv[1]);
|
||||
let mv_patch = parseInt(mv[2]);
|
||||
if(v2_minor == mv_minor) {
|
||||
next_major = release;
|
||||
}
|
||||
@@ -58,6 +60,6 @@ export function getNextVersion(currentVersion, releases) {
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return releases[0];
|
||||
return releases_orig[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
});
|
||||
navigate(sysinfo.usrcfg ? "/" : "/setup");
|
||||
}
|
||||
|
||||
let cc = false;
|
||||
$: {
|
||||
cc = !sysinfo.usrcfg;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="grid xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
|
||||
@@ -38,6 +43,9 @@
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<input type="hidden" name="v" value="true"/>
|
||||
<strong class="text-sm">Initial configuration</strong>
|
||||
{#if sysinfo.usrcfg}
|
||||
<div class="bd-red">WARNING: Changing this configuration will affect basic configuration of your device. Only make changes here if instructed by vendor</div>
|
||||
{/if}
|
||||
<div class="my-3">
|
||||
Board type<br/>
|
||||
<select name="vb" bind:value={sysinfo.board} class="in-s">
|
||||
@@ -53,7 +61,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-3">
|
||||
<label><input type="checkbox" name="vr" value="true" class="rounded mb-1" checked /> Clear all other configuration</label>
|
||||
<label><input type="checkbox" name="vr" value="true" class="rounded mb-1" bind:checked={cc} /> Clear all other configuration</label>
|
||||
</div>
|
||||
<div class="my-3">
|
||||
<button type="submit" class="btn-pri">Save</button>
|
||||
|
||||
@@ -1,48 +1,42 @@
|
||||
<script>
|
||||
import BarChart from './BarChart.svelte';
|
||||
import { voltcol } from './Helpers.js';
|
||||
import { fmtnum, voltcol } from './Helpers.js';
|
||||
|
||||
export let u1;
|
||||
export let u2;
|
||||
export let u3;
|
||||
export let ds;
|
||||
|
||||
let min = 200;
|
||||
let max = 260;
|
||||
let config = {};
|
||||
|
||||
function point(v) {
|
||||
return {
|
||||
label: fmtnum(v) + 'V',
|
||||
value: isNaN(v) ? 0 : v,
|
||||
color: voltcol(v ? v : 0)
|
||||
};
|
||||
};
|
||||
|
||||
$: {
|
||||
let xTicks = [];
|
||||
let points = [];
|
||||
if(u1 > 0) {
|
||||
xTicks.push({ label: ds === 1 ? 'L1-L2' : 'L1' });
|
||||
points.push({
|
||||
label: u1 ? u1.toFixed(0) + 'V' : '-',
|
||||
value: u1 ? u1 : 0,
|
||||
color: voltcol(u1 ? (u1-min)/(max-min)*100 : 0)
|
||||
});
|
||||
points.push(point(u1));
|
||||
}
|
||||
if(u2 > 0) {
|
||||
xTicks.push({ label: ds === 1 ? 'L1-L3' : 'L2' });
|
||||
points.push({
|
||||
label: u2 ? u2.toFixed(0) + 'V' : '-',
|
||||
value: u2 ? u2 : 0,
|
||||
color: voltcol(u2 ? (u2-min)/(max-min)*100 : 0)
|
||||
});
|
||||
points.push(point(u2));
|
||||
}
|
||||
if(u3 > 0) {
|
||||
xTicks.push({ label: ds === 1 ? 'L2-L3' : 'L3' });
|
||||
points.push({
|
||||
label: u3 ? u3.toFixed(0) + 'V' : '-',
|
||||
value: u3 ? u3 : 0,
|
||||
color: voltcol(u3 ? (u3-min)/(max-min)*100 : 0)
|
||||
});
|
||||
points.push(point(u3));
|
||||
}
|
||||
config = {
|
||||
padding: { top: 20, right: 15, bottom: 20, left: 35 },
|
||||
y: {
|
||||
min: min,
|
||||
max: max,
|
||||
min: 200,
|
||||
max: 260,
|
||||
ticks: [
|
||||
{ value: 207, label: '-10%' },
|
||||
{ value: 230, label: '230v' },
|
||||
|
||||
@@ -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.235",
|
||||
"/energyprice.json": "http://192.168.233.235",
|
||||
"/dayplot.json": "http://192.168.233.235",
|
||||
"/monthplot.json": "http://192.168.233.235",
|
||||
"/temperature.json": "http://192.168.233.235",
|
||||
"/sysinfo.json": "http://192.168.233.235",
|
||||
"/configuration.json": "http://192.168.233.235",
|
||||
"/tariff.json": "http://192.168.233.235",
|
||||
"/save": "http://192.168.233.235",
|
||||
"/reboot": "http://192.168.233.235",
|
||||
"/configfile": "http://192.168.233.235",
|
||||
"/upgrade": "http://192.168.233.235"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -73,3 +73,15 @@ lib_compat_mode = off
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:esp32c3]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.mcu = esp32c3
|
||||
build_flags = ${common.build_flags}
|
||||
lib_ldf_mode = off
|
||||
lib_compat_mode = off
|
||||
lib_deps = ${esp32.lib_deps}
|
||||
lib_ignore = ${common.lib_ignore}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
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)) {
|
||||
@@ -1635,7 +1600,7 @@ void configFileParse() {
|
||||
fromHex(meter.encryptionKey, String(buf+19), 16);
|
||||
} else if(strncmp_P(buf, PSTR("meterAuthenticationKey "), 23) == 0) {
|
||||
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
|
||||
fromHex(meter.authenticationKey, String(buf+19), 16);
|
||||
fromHex(meter.authenticationKey, String(buf+23), 16);
|
||||
} else if(strncmp_P(buf, PSTR("gpioHanPin "), 11) == 0) {
|
||||
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
|
||||
gpio.hanPin = String(buf+11).toInt();
|
||||
|
||||