Merge remote-tracking branch 'tbnobody/OpenDTU/master'
@ -87,6 +87,7 @@ Firmware version seems to play not a significant role and cannot be read from th
|
|||||||
* Ethernet support
|
* Ethernet support
|
||||||
* Prometheus API endpoint (/api/prometheus/metrics)
|
* Prometheus API endpoint (/api/prometheus/metrics)
|
||||||
* English, german and french web interface
|
* English, german and french web interface
|
||||||
|
* Displays (SSD1306, SH1106, PCD8544)
|
||||||
|
|
||||||
## Features for developers
|
## Features for developers
|
||||||
* The microcontroller part
|
* The microcontroller part
|
||||||
|
|||||||
@ -30,6 +30,31 @@ To change the device profile, navigate to the "Device Manager" and selected the
|
|||||||
"clk_mode": -1
|
"clk_mode": -1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Generic NodeMCU 38 pin with SSD1306",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 19,
|
||||||
|
"mosi": 23,
|
||||||
|
"clk": 18,
|
||||||
|
"irq": 16,
|
||||||
|
"en": 4,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": false,
|
||||||
|
"phy_addr": -1,
|
||||||
|
"power": -1,
|
||||||
|
"mdc": -1,
|
||||||
|
"mdio": -1,
|
||||||
|
"type": -1,
|
||||||
|
"clk_mode": -1
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": 2,
|
||||||
|
"data": 21,
|
||||||
|
"clk": 22
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Olimex ESP32-POE",
|
"name": "Olimex ESP32-POE",
|
||||||
"nrf24": {
|
"nrf24": {
|
||||||
@ -53,4 +78,28 @@ To change the device profile, navigate to the "Device Manager" and selected the
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
The json file can contain multiple profiles. Each profile requires a name and different parameters. If one parameter is not set, the default value, as compiled into the firmware is used. The example above shows all the currently supported values. Others may follow. A sample file with a lot of boards can be found [here](pin_mapping.json). This means you can just flash the generic bin file and upload the pin_mapping.json file. Then you select your board and everything works hopyfully as expected.
|
The json file can contain multiple profiles. Each profile requires a name and different parameters. If one parameter is not set, the default value, as compiled into the firmware is used. The example above shows all the currently supported values. Others may follow. Sample files for some boards can be found [here](DeviceProfiles/). This means you can just flash the generic bin file and upload the json file. Then you select your board and everything works hopyfully as expected.
|
||||||
|
|
||||||
|
## Implemented configuration values
|
||||||
|
|
||||||
|
| Parameter | Data Type | Description |
|
||||||
|
| ------------- | --------- | ----------- |
|
||||||
|
| name | string | Unique name of the profile (max 63 characters) |
|
||||||
|
| nrf24.miso | number | MISO Pin |
|
||||||
|
| nrf24.mosi | number | MOSI Pin |
|
||||||
|
| nrf24.clk | number | Clock Pin |
|
||||||
|
| nrf24.irq | number | Interrupt Pin |
|
||||||
|
| nrf24.en | number | Enable Pin |
|
||||||
|
| nrf24.cs | number | Chip Select Pin |
|
||||||
|
| eth.enabled | boolean | Enable/Disable the ethernet stack |
|
||||||
|
| eth.phy_addr | number | Unique PHY addr |
|
||||||
|
| eth.power | number | Power Pin (if available). Use -1 for not assigned pins. |
|
||||||
|
| eth.mdc | number | Serial Management Interface MDC Pin. Use -1 for not assigned pins. |
|
||||||
|
| eth.mdio | number | Serial Management Interface MDIO Pin. Use -1 for not assigned pins. |
|
||||||
|
| eth.type | number | Possible values:<br>* 0 = ETH_PHY_LAN8720<br>* 1 = ETH_PHY_TLK110<br>* 2 = ETH_PHY_RTL8201<br>* 3 = ETH_PHY_DP83848<br>* 4 = ETH_PHY_DM9051<br>* 5 = ETH_PHY_KSZ8041<br>* 6 = ETH_PHY_KSZ8081 |
|
||||||
|
| eth.clk_mode | number | Possible values:<br>* 0 = ETH_CLOCK_GPIO0_IN<br>* 1 = ETH_CLOCK_GPIO0_OUT<br>* 2 = ETH_CLOCK_GPIO16_OUT<br>* 3 = ETH_CLOCK_GPIO17_OUT |
|
||||||
|
| display.type | number | Specify type of display. Possible values:<br>* 0 = None (default)<br>* 1 = PCD8544 <br>* 2 = SSD1306 <br>* 3 = SH1106 |
|
||||||
|
| display.data | number | Data Pin (e.g. SDA for i2c displays) required for all displays. Use 255 for not assigned pins. |
|
||||||
|
| display.clk | number | Clock Pin (e.g. SCL for i2c displays) required for SSD1306 and SH1106. Use 255 for not assigned pins. |
|
||||||
|
| display.cs | number | Chip Select Pin required for PCD8544. Use 255 for not assigned pins. |
|
||||||
|
| display.reset | number | Reset Pin required for PCD8544, optional for all other displays. Use 255 for not assigned pins. |
|
||||||
22
docs/DeviceProfiles/lilygo_ttgo_t-internet_poe.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "LILYGO TTGO T-Internet-POE",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 2,
|
||||||
|
"mosi": 15,
|
||||||
|
"clk": 14,
|
||||||
|
"irq": 34,
|
||||||
|
"en": 12,
|
||||||
|
"cs": 4
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 0,
|
||||||
|
"power": -1,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
72
docs/DeviceProfiles/nodemcu_esp32.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Generic NodeMCU 38 pin",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 19,
|
||||||
|
"mosi": 23,
|
||||||
|
"clk": 18,
|
||||||
|
"irq": 16,
|
||||||
|
"en": 4,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": false,
|
||||||
|
"phy_addr": -1,
|
||||||
|
"power": -1,
|
||||||
|
"mdc": -1,
|
||||||
|
"mdio": -1,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Generic NodeMCU 32 with SSD1306",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 19,
|
||||||
|
"mosi": 23,
|
||||||
|
"clk": 18,
|
||||||
|
"irq": 16,
|
||||||
|
"en": 4,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": false,
|
||||||
|
"phy_addr": -1,
|
||||||
|
"power": -1,
|
||||||
|
"mdc": -1,
|
||||||
|
"mdio": -1,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 0
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": 2,
|
||||||
|
"data": 21,
|
||||||
|
"clk": 22
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Generic NodeMCU 32 with SH1106",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 19,
|
||||||
|
"mosi": 23,
|
||||||
|
"clk": 18,
|
||||||
|
"irq": 16,
|
||||||
|
"en": 4,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": false,
|
||||||
|
"phy_addr": -1,
|
||||||
|
"power": -1,
|
||||||
|
"mdc": -1,
|
||||||
|
"mdio": -1,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 0
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": 3,
|
||||||
|
"data": 21,
|
||||||
|
"clk": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
22
docs/DeviceProfiles/olimex_esp32_evb.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Olimex ESP32-EVB",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 15,
|
||||||
|
"mosi": 2,
|
||||||
|
"clk": 14,
|
||||||
|
"irq": 13,
|
||||||
|
"en": 16,
|
||||||
|
"cs": 17
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 0,
|
||||||
|
"power": 12,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
72
docs/DeviceProfiles/olimex_esp32_poe.json
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Olimex ESP32-POE",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 15,
|
||||||
|
"mosi": 2,
|
||||||
|
"clk": 14,
|
||||||
|
"irq": 13,
|
||||||
|
"en": 16,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 0,
|
||||||
|
"power": 12,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Olimex ESP32-POE with SSD1306",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 15,
|
||||||
|
"mosi": 2,
|
||||||
|
"clk": 14,
|
||||||
|
"irq": 13,
|
||||||
|
"en": 16,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 0,
|
||||||
|
"power": 12,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 3
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": 2,
|
||||||
|
"data": 33,
|
||||||
|
"clk": 32
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Olimex ESP32-POE with SH1106",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 15,
|
||||||
|
"mosi": 2,
|
||||||
|
"clk": 14,
|
||||||
|
"irq": 13,
|
||||||
|
"en": 16,
|
||||||
|
"cs": 5
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 0,
|
||||||
|
"power": 12,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 3
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": 2,
|
||||||
|
"data": 33,
|
||||||
|
"clk": 32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
22
docs/DeviceProfiles/wt32-eth01.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "WT32-ETH01",
|
||||||
|
"nrf24": {
|
||||||
|
"miso": 4,
|
||||||
|
"mosi": 2,
|
||||||
|
"clk": 32,
|
||||||
|
"irq": 33,
|
||||||
|
"en": 14,
|
||||||
|
"cs": 15
|
||||||
|
},
|
||||||
|
"eth": {
|
||||||
|
"enabled": true,
|
||||||
|
"phy_addr": 1,
|
||||||
|
"power": 16,
|
||||||
|
"mdc": 23,
|
||||||
|
"mdio": 18,
|
||||||
|
"type": 0,
|
||||||
|
"clk_mode": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
20
docs/Display.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Display integration
|
||||||
|
|
||||||
|
OpenDTU currently supports 3 types of displays (SSD1306, SH1106 and PCD8544). Currently only displays with a resolution of 128x64 pixel are supported. To activate a display you have to specify it's type and pin assignment either in the `platformio_override.ini` or in a device profile. Due to the fact that device profiles work with the pre-compiled binary the following documentation will only cover the device profile method.
|
||||||
|
|
||||||
|
You can either create your own device profile as described [here](DeviceProfiles.md) or use some pre-defined. The pre-defined profiles can be found [here](DeviceProfiles/). You can simply open the json file with a text editor of your choice to view/edit the pin assignment.
|
||||||
|
|
||||||
|
## Uploading Device Profiles
|
||||||
|
|
||||||
|
Use the "Config Management" site to upload (Restore) the json file. Make sure to choose "Pin Mapping (pin_mapping.json)" in the combo box. After you click on restore the ESP will restart. At this point, the profile is not yet active. Please read the next chapter.
|
||||||
|

|
||||||
|
|
||||||
|
## Selecting the a Device Profile
|
||||||
|
|
||||||
|
After you uploaded the device profile you can select the profile in the "Device Manager" view. After a click on "Save" the ESP will be restarted and the pin assignment is active. At this point the display should already show something. Please see the next chapter for display settings.
|
||||||
|

|
||||||
|
|
||||||
|
## Display Settings
|
||||||
|
|
||||||
|
Display settings can also be found in the "Device Manager".
|
||||||
|

|
||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
More detailed descriptions for some topics can be found here.
|
More detailed descriptions for some topics can be found here.
|
||||||
|
|
||||||
|
## [Display Documentation](Display.md)
|
||||||
## [MQTT Topic Documentation](MQTT_Topics.md)
|
## [MQTT Topic Documentation](MQTT_Topics.md)
|
||||||
## [Web API Documentation](Web-API.md)
|
## [Web API Documentation](Web-API.md)
|
||||||
## [Device Profile Documentation](DeviceProfiles.md)
|
## [Device Profile Documentation](DeviceProfiles.md)
|
||||||
|
|||||||
@ -1,122 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"name": "Generic NodeMCU 38 pin",
|
|
||||||
"nrf24": {
|
|
||||||
"miso": 19,
|
|
||||||
"mosi": 23,
|
|
||||||
"clk": 18,
|
|
||||||
"irq": 16,
|
|
||||||
"en": 4,
|
|
||||||
"cs": 5
|
|
||||||
},
|
|
||||||
"eth": {
|
|
||||||
"enabled": false,
|
|
||||||
"phy_addr": -1,
|
|
||||||
"power": -1,
|
|
||||||
"mdc": -1,
|
|
||||||
"mdio": -1,
|
|
||||||
"type": -1,
|
|
||||||
"clk_mode": -1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Olimex ESP32-POE",
|
|
||||||
"nrf24": {
|
|
||||||
"miso": 15,
|
|
||||||
"mosi": 2,
|
|
||||||
"clk": 14,
|
|
||||||
"irq": 13,
|
|
||||||
"en": 16,
|
|
||||||
"cs": 5
|
|
||||||
},
|
|
||||||
"eth": {
|
|
||||||
"enabled": true,
|
|
||||||
"phy_addr": 0,
|
|
||||||
"power": 12,
|
|
||||||
"mdc": 23,
|
|
||||||
"mdio": 18,
|
|
||||||
"type": 0,
|
|
||||||
"clk_mode": 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Olimex ESP32-EVB",
|
|
||||||
"nrf24": {
|
|
||||||
"miso": 15,
|
|
||||||
"mosi": 2,
|
|
||||||
"clk": 14,
|
|
||||||
"irq": 13,
|
|
||||||
"en": 16,
|
|
||||||
"cs": 17
|
|
||||||
},
|
|
||||||
"eth": {
|
|
||||||
"enabled": true,
|
|
||||||
"phy_addr": 0,
|
|
||||||
"power": 12,
|
|
||||||
"mdc": 23,
|
|
||||||
"mdio": 18,
|
|
||||||
"type": 0,
|
|
||||||
"clk_mode": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Generic NodeMCU 30 pin",
|
|
||||||
"nrf24": {
|
|
||||||
"miso": 19,
|
|
||||||
"mosi": 23,
|
|
||||||
"clk": 18,
|
|
||||||
"irq": 16,
|
|
||||||
"en": 17,
|
|
||||||
"cs": 5
|
|
||||||
},
|
|
||||||
"eth": {
|
|
||||||
"enabled": false,
|
|
||||||
"phy_addr": -1,
|
|
||||||
"power": -1,
|
|
||||||
"mdc": -1,
|
|
||||||
"mdio": -1,
|
|
||||||
"type": -1,
|
|
||||||
"clk_mode": -1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "WT32-ETH01",
|
|
||||||
"nrf24": {
|
|
||||||
"miso": 4,
|
|
||||||
"mosi": 2,
|
|
||||||
"clk": 32,
|
|
||||||
"irq": 33,
|
|
||||||
"en": 14,
|
|
||||||
"cs": 15
|
|
||||||
},
|
|
||||||
"eth": {
|
|
||||||
"enabled": true,
|
|
||||||
"phy_addr": 1,
|
|
||||||
"power": 16,
|
|
||||||
"mdc": 23,
|
|
||||||
"mdio": 18,
|
|
||||||
"type": 0,
|
|
||||||
"clk_mode": 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "LILYGO TTGO T-Internet-POE",
|
|
||||||
"nrf24": {
|
|
||||||
"miso": 2,
|
|
||||||
"mosi": 15,
|
|
||||||
"clk": 14,
|
|
||||||
"irq": 34,
|
|
||||||
"en": 12,
|
|
||||||
"cs": 4
|
|
||||||
},
|
|
||||||
"eth": {
|
|
||||||
"enabled": true,
|
|
||||||
"phy_addr": 0,
|
|
||||||
"power": -1,
|
|
||||||
"mdc": 23,
|
|
||||||
"mdio": 18,
|
|
||||||
"type": 0,
|
|
||||||
"clk_mode": 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 38 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 21 KiB |
BIN
docs/screenshots/18_Console.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/screenshots/19_Reboot.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/screenshots/20_DeviceManager_Pin.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/screenshots/21_DeviceManager_Display.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/screenshots/22_Security.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
@ -8,6 +8,18 @@ here are some screenshots of OpenDTU's web interface.
|
|||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
***
|
***
|
||||||
@ -24,14 +36,42 @@ here are some screenshots of OpenDTU's web interface.
|
|||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
***
|
***
|
||||||
@ -44,28 +84,8 @@ here are some screenshots of OpenDTU's web interface.
|
|||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
***
|
|
||||||
|
|
||||||

|
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#define CHAN_MAX_NAME_STRLEN 31
|
#define CHAN_MAX_NAME_STRLEN 31
|
||||||
|
|
||||||
#define DEV_MAX_MAPPING_NAME_STRLEN 31
|
#define DEV_MAX_MAPPING_NAME_STRLEN 63
|
||||||
|
|
||||||
#define JSON_BUFFER_SIZE 6144
|
#define JSON_BUFFER_SIZE 6144
|
||||||
|
|
||||||
@ -96,6 +96,11 @@ struct CONFIG_T {
|
|||||||
bool Security_AllowReadonly;
|
bool Security_AllowReadonly;
|
||||||
|
|
||||||
char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1];
|
char Dev_PinMapping[DEV_MAX_MAPPING_NAME_STRLEN + 1];
|
||||||
|
|
||||||
|
bool Display_PowerSafe;
|
||||||
|
bool Display_ScreenSaver;
|
||||||
|
bool Display_ShowLogo;
|
||||||
|
uint8_t Display_Contrast;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfigurationClass {
|
class ConfigurationClass {
|
||||||
|
|||||||
41
include/Display_Graphic.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <U8g2lib.h>
|
||||||
|
|
||||||
|
enum DisplayType_t {
|
||||||
|
None,
|
||||||
|
PCD8544,
|
||||||
|
SSD1306,
|
||||||
|
SH1106,
|
||||||
|
};
|
||||||
|
|
||||||
|
class DisplayGraphicClass {
|
||||||
|
public:
|
||||||
|
DisplayGraphicClass();
|
||||||
|
~DisplayGraphicClass();
|
||||||
|
|
||||||
|
void init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset);
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
bool enablePowerSafe = true;
|
||||||
|
bool enableScreensaver = true;
|
||||||
|
bool showLogo = true;
|
||||||
|
uint8_t contrast = 60;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printText(const char* text, uint8_t line);
|
||||||
|
|
||||||
|
U8G2* _display;
|
||||||
|
|
||||||
|
DisplayType_t _display_type = DisplayType_t::None;
|
||||||
|
uint8_t _mExtra;
|
||||||
|
uint16_t _dispY = 0;
|
||||||
|
uint16_t _period = 1000;
|
||||||
|
uint16_t _interval = 60000; // interval at which to power save (milliseconds)
|
||||||
|
uint32_t _lastDisplayUpdate = 0;
|
||||||
|
uint32_t _previousMillis = 0;
|
||||||
|
char _fmtText[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DisplayGraphicClass Display;
|
||||||
@ -24,6 +24,11 @@ struct PinMapping_t {
|
|||||||
int eth_mdio;
|
int eth_mdio;
|
||||||
eth_phy_type_t eth_type;
|
eth_phy_type_t eth_type;
|
||||||
eth_clock_mode_t eth_clk_mode;
|
eth_clock_mode_t eth_clk_mode;
|
||||||
|
uint8_t display_type;
|
||||||
|
uint8_t display_data;
|
||||||
|
uint8_t display_clk;
|
||||||
|
uint8_t display_cs;
|
||||||
|
uint8_t display_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PinMappingClass {
|
class PinMappingClass {
|
||||||
|
|||||||
@ -81,6 +81,11 @@
|
|||||||
|
|
||||||
#define DEV_PINMAPPING ""
|
#define DEV_PINMAPPING ""
|
||||||
|
|
||||||
|
#define DISPLAY_POWERSAFE true
|
||||||
|
#define DISPLAY_SCREENSAVER true
|
||||||
|
#define DISPLAY_SHOWLOGO true
|
||||||
|
#define DISPLAY_CONTRAST 60
|
||||||
|
|
||||||
#define VEDIRECT_ENABLED false
|
#define VEDIRECT_ENABLED false
|
||||||
#define VEDIRECT_UPDATESONLY true
|
#define VEDIRECT_UPDATESONLY true
|
||||||
#define VEDIRECT_POLL_INTERVAL 5
|
#define VEDIRECT_POLL_INTERVAL 5
|
||||||
@ -26,6 +26,7 @@ lib_deps =
|
|||||||
bblanchon/ArduinoJson @ ^6.20.0
|
bblanchon/ArduinoJson @ ^6.20.0
|
||||||
https://github.com/bertmelis/espMqttClient.git#v1.3.3
|
https://github.com/bertmelis/espMqttClient.git#v1.3.3
|
||||||
nrf24/RF24 @ ^1.4.5
|
nrf24/RF24 @ ^1.4.5
|
||||||
|
olikraus/U8g2 @ ^2.34.13
|
||||||
|
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
pre:auto_firmware_version.py
|
pre:auto_firmware_version.py
|
||||||
|
|||||||
@ -83,6 +83,12 @@ bool ConfigurationClass::write()
|
|||||||
JsonObject device = doc.createNestedObject("device");
|
JsonObject device = doc.createNestedObject("device");
|
||||||
device["pinmapping"] = config.Dev_PinMapping;
|
device["pinmapping"] = config.Dev_PinMapping;
|
||||||
|
|
||||||
|
JsonObject display = device.createNestedObject("display");
|
||||||
|
display["powersafe"] = config.Display_PowerSafe;
|
||||||
|
display["screensaver"] = config.Display_ScreenSaver;
|
||||||
|
display["showlogo"] = config.Display_ShowLogo;
|
||||||
|
display["contrast"] = config.Display_Contrast;
|
||||||
|
|
||||||
JsonArray inverters = doc.createNestedArray("inverters");
|
JsonArray inverters = doc.createNestedArray("inverters");
|
||||||
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
||||||
JsonObject inv = inverters.createNestedObject();
|
JsonObject inv = inverters.createNestedObject();
|
||||||
@ -212,6 +218,12 @@ bool ConfigurationClass::read()
|
|||||||
JsonObject device = doc["device"];
|
JsonObject device = doc["device"];
|
||||||
strlcpy(config.Dev_PinMapping, device["pinmapping"] | DEV_PINMAPPING, sizeof(config.Dev_PinMapping));
|
strlcpy(config.Dev_PinMapping, device["pinmapping"] | DEV_PINMAPPING, sizeof(config.Dev_PinMapping));
|
||||||
|
|
||||||
|
JsonObject display = device["display"];
|
||||||
|
config.Display_PowerSafe = display["powersafe"] | DISPLAY_POWERSAFE;
|
||||||
|
config.Display_ScreenSaver = display["screensaver"] | DISPLAY_SCREENSAVER;
|
||||||
|
config.Display_ShowLogo = display["showlogo"] | DISPLAY_SHOWLOGO;
|
||||||
|
config.Display_Contrast = display["contrast"] | DISPLAY_CONTRAST;
|
||||||
|
|
||||||
JsonArray inverters = doc["inverters"];
|
JsonArray inverters = doc["inverters"];
|
||||||
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
for (uint8_t i = 0; i < INV_MAX_COUNT; i++) {
|
||||||
JsonObject inv = inverters[i].as<JsonObject>();
|
JsonObject inv = inverters[i].as<JsonObject>();
|
||||||
|
|||||||
198
src/Display_Graphic.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
#include "Display_Graphic.h"
|
||||||
|
#include <Hoymiles.h>
|
||||||
|
#include <NetworkSettings.h>
|
||||||
|
#include <map>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
static uint8_t bmp_logo[] PROGMEM = {
|
||||||
|
B00000000, B00000000, // ................
|
||||||
|
B11101100, B00110111, // ..##.######.##..
|
||||||
|
B11101100, B00110111, // ..##.######.##..
|
||||||
|
B11100000, B00000111, // .....######.....
|
||||||
|
B11010000, B00001011, // ....#.####.#....
|
||||||
|
B10011000, B00011001, // ...##..##..##...
|
||||||
|
B10000000, B00000001, // .......##.......
|
||||||
|
B00000000, B00000000, // ................
|
||||||
|
B01111000, B00011110, // ...####..####...
|
||||||
|
B11111100, B00111111, // ..############..
|
||||||
|
B01111100, B00111110, // ..#####..#####..
|
||||||
|
B00000000, B00000000, // ................
|
||||||
|
B11111100, B00111111, // ..############..
|
||||||
|
B11111110, B01111111, // .##############.
|
||||||
|
B01111110, B01111110, // .######..######.
|
||||||
|
B00000000, B00000000 // ................
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t bmp_arrow[] PROGMEM = {
|
||||||
|
B00000000, B00011100, B00011100, B00001110, B00001110, B11111110, B01111111,
|
||||||
|
B01110000, B01110000, B00110000, B00111000, B00011000, B01111111, B00111111,
|
||||||
|
B00011110, B00001110, B00000110, B00000000, B00000000, B00000000, B00000000
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>> display_types = {
|
||||||
|
{ DisplayType_t::PCD8544, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_PCD8544_84X48_F_4W_HW_SPI(U8G2_R0, cs, data, reset); } },
|
||||||
|
{ DisplayType_t::SSD1306, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } },
|
||||||
|
{ DisplayType_t::SH1106, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_SH1106_128X64_NONAME_F_HW_I2C(U8G2_R0, reset, clock, data); } },
|
||||||
|
};
|
||||||
|
|
||||||
|
DisplayGraphicClass::DisplayGraphicClass()
|
||||||
|
{}
|
||||||
|
|
||||||
|
DisplayGraphicClass::~DisplayGraphicClass()
|
||||||
|
{
|
||||||
|
delete _display;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayGraphicClass::init(DisplayType_t type, uint8_t data, uint8_t clk, uint8_t cs, uint8_t reset)
|
||||||
|
{
|
||||||
|
_display_type = type;
|
||||||
|
if (_display_type > DisplayType_t::None) {
|
||||||
|
auto constructor = display_types[_display_type];
|
||||||
|
_display = constructor(reset, clk, data, cs);
|
||||||
|
_display->begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayGraphicClass::printText(const char* text, uint8_t line)
|
||||||
|
{
|
||||||
|
// get the width and height of the display
|
||||||
|
uint16_t maxWidth = _display->getWidth();
|
||||||
|
uint16_t maxHeight = _display->getHeight();
|
||||||
|
|
||||||
|
// pxMovement +x (0 - 6 px)
|
||||||
|
uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0;
|
||||||
|
|
||||||
|
// set the font size based on the display size
|
||||||
|
switch (line) {
|
||||||
|
case 1:
|
||||||
|
if (maxWidth > 120 && maxHeight > 60) {
|
||||||
|
_display->setFont(u8g2_font_ncenB14_tr); // large display
|
||||||
|
} else {
|
||||||
|
_display->setFont(u8g2_font_logisoso16_tr); // small display
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (maxWidth > 120 && maxHeight > 60) {
|
||||||
|
_display->setFont(u8g2_font_5x8_tr); // large display
|
||||||
|
} else {
|
||||||
|
_display->setFont(u8g2_font_5x8_tr); // small display
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (maxWidth > 120 && maxHeight > 60) {
|
||||||
|
_display->setFont(u8g2_font_ncenB10_tr); // large display
|
||||||
|
} else {
|
||||||
|
_display->setFont(u8g2_font_5x8_tr); // small display
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the font height, to calculate the textheight
|
||||||
|
_dispY += (_display->getMaxCharHeight()) + 1;
|
||||||
|
|
||||||
|
// calculate the starting position of the text
|
||||||
|
uint16_t dispX;
|
||||||
|
if (line == 1) {
|
||||||
|
dispX = 20 + ex;
|
||||||
|
} else {
|
||||||
|
dispX = 5 + ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw the Text, on the calculated pos
|
||||||
|
_display->drawStr(dispX, _dispY, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayGraphicClass::loop()
|
||||||
|
{
|
||||||
|
if (_display_type == DisplayType_t::None) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((millis() - _lastDisplayUpdate) > _period) {
|
||||||
|
float totalPower = 0;
|
||||||
|
float totalYieldDay = 0;
|
||||||
|
float totalYieldTotal = 0;
|
||||||
|
|
||||||
|
uint8_t isprod = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) {
|
||||||
|
auto inv = Hoymiles.getInverterByPos(i);
|
||||||
|
if (inv == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inv->isProducing()) {
|
||||||
|
isprod++;
|
||||||
|
}
|
||||||
|
|
||||||
|
totalPower += inv->Statistics()->getChannelFieldValue(CH0, FLD_PAC);
|
||||||
|
totalYieldDay += inv->Statistics()->getChannelFieldValue(CH0, FLD_YD);
|
||||||
|
totalYieldTotal += inv->Statistics()->getChannelFieldValue(CH0, FLD_YT);
|
||||||
|
}
|
||||||
|
|
||||||
|
_display->clearBuffer();
|
||||||
|
|
||||||
|
// set Contrast of the Display to raise the lifetime
|
||||||
|
_display->setContrast(contrast);
|
||||||
|
|
||||||
|
//=====> Logo and Lighting ==========
|
||||||
|
// pxMovement +x (0 - 6 px)
|
||||||
|
uint8_t ex = enableScreensaver ? (_mExtra % 7) : 0;
|
||||||
|
if (isprod > 0) {
|
||||||
|
_display->drawXBMP(5 + ex, 1, 8, 17, bmp_arrow);
|
||||||
|
if (showLogo) {
|
||||||
|
_display->drawXBMP(_display->getWidth() - 24 + ex, 2, 16, 16, bmp_logo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//<=======================
|
||||||
|
|
||||||
|
//=====> Actual Production ==========
|
||||||
|
if ((totalPower > 0) && (isprod > 0)) {
|
||||||
|
_display->setPowerSave(false);
|
||||||
|
if (totalPower > 999) {
|
||||||
|
snprintf(_fmtText, sizeof(_fmtText), "%2.1f kW", (totalPower / 1000));
|
||||||
|
} else {
|
||||||
|
snprintf(_fmtText, sizeof(_fmtText), "%3.0f W", totalPower);
|
||||||
|
}
|
||||||
|
printText(_fmtText, 1);
|
||||||
|
_previousMillis = millis();
|
||||||
|
}
|
||||||
|
//<=======================
|
||||||
|
|
||||||
|
//=====> Offline ===========
|
||||||
|
else {
|
||||||
|
printText("offline", 1);
|
||||||
|
// check if it's time to enter power saving mode
|
||||||
|
if (millis() - _previousMillis >= (_interval * 2)) {
|
||||||
|
_display->setPowerSave(enablePowerSafe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//<=======================
|
||||||
|
|
||||||
|
//=====> Today & Total Production =======
|
||||||
|
snprintf(_fmtText, sizeof(_fmtText), "today: %4.0f Wh", totalYieldDay);
|
||||||
|
printText(_fmtText, 2);
|
||||||
|
|
||||||
|
snprintf(_fmtText, sizeof(_fmtText), "total: %.1f kWh", totalYieldTotal);
|
||||||
|
printText(_fmtText, 3);
|
||||||
|
//<=======================
|
||||||
|
|
||||||
|
//=====> IP or Date-Time ========
|
||||||
|
if (!(_mExtra % 10) && NetworkSettings.localIP()) {
|
||||||
|
printText(NetworkSettings.localIP().toString().c_str(), 4);
|
||||||
|
} else {
|
||||||
|
// Get current time
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
strftime(_fmtText, sizeof(_fmtText), "%a %d.%m.%Y %H:%M", localtime(&now));
|
||||||
|
printText(_fmtText, 4);
|
||||||
|
}
|
||||||
|
_display->sendBuffer();
|
||||||
|
|
||||||
|
_dispY = 0;
|
||||||
|
_mExtra++;
|
||||||
|
_lastDisplayUpdate = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayGraphicClass Display;
|
||||||
@ -10,6 +10,26 @@
|
|||||||
|
|
||||||
#define JSON_BUFFER_SIZE 6144
|
#define JSON_BUFFER_SIZE 6144
|
||||||
|
|
||||||
|
#ifndef DISPLAY_TYPE
|
||||||
|
#define DISPLAY_TYPE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DISPLAY_DATA
|
||||||
|
#define DISPLAY_DATA 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DISPLAY_CLK
|
||||||
|
#define DISPLAY_CLK 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DISPLAY_CS
|
||||||
|
#define DISPLAY_CS 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DISPLAY_RESET
|
||||||
|
#define DISPLAY_RESET 255
|
||||||
|
#endif
|
||||||
|
|
||||||
PinMappingClass PinMapping;
|
PinMappingClass PinMapping;
|
||||||
|
|
||||||
PinMappingClass::PinMappingClass()
|
PinMappingClass::PinMappingClass()
|
||||||
@ -34,6 +54,13 @@ PinMappingClass::PinMappingClass()
|
|||||||
_pinMapping.eth_mdio = ETH_PHY_MDIO;
|
_pinMapping.eth_mdio = ETH_PHY_MDIO;
|
||||||
_pinMapping.eth_type = ETH_PHY_TYPE;
|
_pinMapping.eth_type = ETH_PHY_TYPE;
|
||||||
_pinMapping.eth_clk_mode = ETH_CLK_MODE;
|
_pinMapping.eth_clk_mode = ETH_CLK_MODE;
|
||||||
|
|
||||||
|
_pinMapping.display_type = DISPLAY_TYPE;
|
||||||
|
_pinMapping.display_data = DISPLAY_DATA;
|
||||||
|
_pinMapping.display_clk = DISPLAY_CLK;
|
||||||
|
_pinMapping.display_cs = DISPLAY_CS;
|
||||||
|
_pinMapping.display_reset = DISPLAY_RESET;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PinMapping_t& PinMappingClass::get()
|
PinMapping_t& PinMappingClass::get()
|
||||||
@ -80,6 +107,12 @@ bool PinMappingClass::init(const String& deviceMapping)
|
|||||||
_pinMapping.eth_type = doc[i]["eth"]["type"] | ETH_PHY_TYPE;
|
_pinMapping.eth_type = doc[i]["eth"]["type"] | ETH_PHY_TYPE;
|
||||||
_pinMapping.eth_clk_mode = doc[i]["eth"]["clk_mode"] | ETH_CLK_MODE;
|
_pinMapping.eth_clk_mode = doc[i]["eth"]["clk_mode"] | ETH_CLK_MODE;
|
||||||
|
|
||||||
|
_pinMapping.display_type = doc[i]["display"]["type"] | DISPLAY_TYPE;
|
||||||
|
_pinMapping.display_data = doc[i]["display"]["data"] | DISPLAY_DATA;
|
||||||
|
_pinMapping.display_clk = doc[i]["display"]["clk"] | DISPLAY_CLK;
|
||||||
|
_pinMapping.display_cs = doc[i]["display"]["cs"] | DISPLAY_CS;
|
||||||
|
_pinMapping.display_reset = doc[i]["display"]["reset"] | DISPLAY_RESET;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "WebApi_device.h"
|
#include "WebApi_device.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
|
#include "Display_Graphic.h"
|
||||||
#include "PinMapping.h"
|
#include "PinMapping.h"
|
||||||
#include "WebApi.h"
|
#include "WebApi.h"
|
||||||
#include "WebApi_errors.h"
|
#include "WebApi_errors.h"
|
||||||
@ -38,22 +39,35 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
|
|||||||
JsonObject curPin = root.createNestedObject("curPin");
|
JsonObject curPin = root.createNestedObject("curPin");
|
||||||
curPin[F("name")] = config.Dev_PinMapping;
|
curPin[F("name")] = config.Dev_PinMapping;
|
||||||
|
|
||||||
JsonObject nrfObj = curPin.createNestedObject("nrf24");
|
JsonObject nrfPinObj = curPin.createNestedObject("nrf24");
|
||||||
nrfObj[F("clk")] = pin.nrf24_clk;
|
nrfPinObj[F("clk")] = pin.nrf24_clk;
|
||||||
nrfObj[F("cs")] = pin.nrf24_cs;
|
nrfPinObj[F("cs")] = pin.nrf24_cs;
|
||||||
nrfObj[F("en")] = pin.nrf24_en;
|
nrfPinObj[F("en")] = pin.nrf24_en;
|
||||||
nrfObj[F("irq")] = pin.nrf24_irq;
|
nrfPinObj[F("irq")] = pin.nrf24_irq;
|
||||||
nrfObj[F("miso")] = pin.nrf24_miso;
|
nrfPinObj[F("miso")] = pin.nrf24_miso;
|
||||||
nrfObj[F("mosi")] = pin.nrf24_mosi;
|
nrfPinObj[F("mosi")] = pin.nrf24_mosi;
|
||||||
|
|
||||||
JsonObject ethObj = curPin.createNestedObject("eth");
|
JsonObject ethPinObj = curPin.createNestedObject("eth");
|
||||||
ethObj[F("enabled")] = pin.eth_enabled;
|
ethPinObj[F("enabled")] = pin.eth_enabled;
|
||||||
ethObj[F("phy_addr")] = pin.eth_phy_addr;
|
ethPinObj[F("phy_addr")] = pin.eth_phy_addr;
|
||||||
ethObj[F("power")] = pin.eth_power;
|
ethPinObj[F("power")] = pin.eth_power;
|
||||||
ethObj[F("mdc")] = pin.eth_mdc;
|
ethPinObj[F("mdc")] = pin.eth_mdc;
|
||||||
ethObj[F("mdio")] = pin.eth_mdio;
|
ethPinObj[F("mdio")] = pin.eth_mdio;
|
||||||
ethObj[F("type")] = pin.eth_type;
|
ethPinObj[F("type")] = pin.eth_type;
|
||||||
ethObj[F("clk_mode")] = pin.eth_clk_mode;
|
ethPinObj[F("clk_mode")] = pin.eth_clk_mode;
|
||||||
|
|
||||||
|
JsonObject displayPinObj = curPin.createNestedObject("display");
|
||||||
|
displayPinObj[F("type")] = pin.display_type;
|
||||||
|
displayPinObj[F("data")] = pin.display_data;
|
||||||
|
displayPinObj[F("clk")] = pin.display_clk;
|
||||||
|
displayPinObj[F("cs")] = pin.display_cs;
|
||||||
|
displayPinObj[F("reset")] = pin.display_reset;
|
||||||
|
|
||||||
|
JsonObject display = root.createNestedObject("display");
|
||||||
|
display[F("show_logo")] = config.Display_ShowLogo;
|
||||||
|
display[F("power_safe")] = config.Display_PowerSafe;
|
||||||
|
display[F("screensaver")] = config.Display_ScreenSaver;
|
||||||
|
display[F("contrast")] = config.Display_Contrast;
|
||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -98,7 +112,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("curPin"))) {
|
if (!(root.containsKey("curPin") || root.containsKey("display"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg[F("message")] = F("Values are missing!");
|
||||||
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
retMsg[F("code")] = WebApiError::GenericValueMissing;
|
||||||
response->setLength();
|
response->setLength();
|
||||||
@ -116,7 +130,19 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
bool performRestart = root[F("curPin")][F("name")].as<String>() != config.Dev_PinMapping;
|
||||||
|
|
||||||
strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as<String>().c_str(), sizeof(config.Dev_PinMapping));
|
strlcpy(config.Dev_PinMapping, root[F("curPin")][F("name")].as<String>().c_str(), sizeof(config.Dev_PinMapping));
|
||||||
|
config.Display_ShowLogo = root[F("display")][F("show_logo")].as<bool>();
|
||||||
|
config.Display_PowerSafe = root[F("display")][F("power_safe")].as<bool>();
|
||||||
|
config.Display_ScreenSaver = root[F("display")][F("screensaver")].as<bool>();
|
||||||
|
config.Display_Contrast = root[F("display")][F("contrast")].as<uint8_t>();
|
||||||
|
|
||||||
|
Display.showLogo = config.Display_ShowLogo;
|
||||||
|
Display.enablePowerSafe = config.Display_PowerSafe;
|
||||||
|
Display.enableScreensaver = config.Display_ScreenSaver;
|
||||||
|
Display.contrast = config.Display_Contrast;
|
||||||
|
|
||||||
Configuration.write();
|
Configuration.write();
|
||||||
|
|
||||||
retMsg[F("type")] = F("success");
|
retMsg[F("type")] = F("success");
|
||||||
@ -126,8 +152,10 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
|
|||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|
||||||
|
if (performRestart) {
|
||||||
yield();
|
yield();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
yield();
|
yield();
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
21
src/main.cpp
@ -3,6 +3,7 @@
|
|||||||
* Copyright (C) 2022 Thomas Basler and others
|
* Copyright (C) 2022 Thomas Basler and others
|
||||||
*/
|
*/
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
|
#include "Display_Graphic.h"
|
||||||
#include "MessageOutput.h"
|
#include "MessageOutput.h"
|
||||||
#include "VeDirectFrameHandler.h"
|
#include "VeDirectFrameHandler.h"
|
||||||
#include "MqttHandleDtu.h"
|
#include "MqttHandleDtu.h"
|
||||||
@ -57,6 +58,7 @@ void setup()
|
|||||||
MessageOutput.print(F("migrated... "));
|
MessageOutput.print(F("migrated... "));
|
||||||
Configuration.migrate();
|
Configuration.migrate();
|
||||||
}
|
}
|
||||||
|
CONFIG_T& config = Configuration.get();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println(F("done"));
|
||||||
|
|
||||||
// Load PinMapping
|
// Load PinMapping
|
||||||
@ -66,6 +68,7 @@ void setup()
|
|||||||
} else {
|
} else {
|
||||||
MessageOutput.print(F("using default config "));
|
MessageOutput.print(F("using default config "));
|
||||||
}
|
}
|
||||||
|
const PinMapping_t& pin = PinMapping.get();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println(F("done"));
|
||||||
|
|
||||||
// Initialize WiFi
|
// Initialize WiFi
|
||||||
@ -93,9 +96,22 @@ void setup()
|
|||||||
WebApi.init();
|
WebApi.init();
|
||||||
MessageOutput.println(F("done"));
|
MessageOutput.println(F("done"));
|
||||||
|
|
||||||
|
// Initialize Display
|
||||||
|
MessageOutput.print(F("Initialize Display... "));
|
||||||
|
Display.init(
|
||||||
|
static_cast<DisplayType_t>(pin.display_type),
|
||||||
|
pin.display_data,
|
||||||
|
pin.display_clk,
|
||||||
|
pin.display_cs,
|
||||||
|
pin.display_reset);
|
||||||
|
Display.showLogo = config.Display_ShowLogo;
|
||||||
|
Display.enablePowerSafe = config.Display_PowerSafe;
|
||||||
|
Display.enableScreensaver = config.Display_ScreenSaver;
|
||||||
|
Display.contrast = config.Display_Contrast;
|
||||||
|
MessageOutput.println(F("done"));
|
||||||
|
|
||||||
// Check for default DTU serial
|
// Check for default DTU serial
|
||||||
MessageOutput.print(F("Check for default DTU serial... "));
|
MessageOutput.print(F("Check for default DTU serial... "));
|
||||||
CONFIG_T& config = Configuration.get();
|
|
||||||
if (config.Dtu_Serial == DTU_SERIAL) {
|
if (config.Dtu_Serial == DTU_SERIAL) {
|
||||||
MessageOutput.print(F("generate serial based on ESP chip id: "));
|
MessageOutput.print(F("generate serial based on ESP chip id: "));
|
||||||
uint64_t dtuId = Utils::generateDtuSerial();
|
uint64_t dtuId = Utils::generateDtuSerial();
|
||||||
@ -111,7 +127,6 @@ void setup()
|
|||||||
MessageOutput.print(F("Initialize Hoymiles interface... "));
|
MessageOutput.print(F("Initialize Hoymiles interface... "));
|
||||||
if (PinMapping.isValidNrf24Config()) {
|
if (PinMapping.isValidNrf24Config()) {
|
||||||
SPIClass* spiClass = new SPIClass(HSPI);
|
SPIClass* spiClass = new SPIClass(HSPI);
|
||||||
PinMapping_t& pin = PinMapping.get();
|
|
||||||
spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs);
|
spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs);
|
||||||
Hoymiles.setMessageOutput(&MessageOutput);
|
Hoymiles.setMessageOutput(&MessageOutput);
|
||||||
Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq);
|
Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq);
|
||||||
@ -177,6 +192,8 @@ void loop()
|
|||||||
yield();
|
yield();
|
||||||
WebApi.loop();
|
WebApi.loop();
|
||||||
yield();
|
yield();
|
||||||
|
Display.loop();
|
||||||
|
yield();
|
||||||
MessageOutput.loop();
|
MessageOutput.loop();
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
@ -80,6 +80,33 @@
|
|||||||
<td>{{ currentPinAssignment?.eth?.clk_mode }}</td>
|
<td>{{ currentPinAssignment?.eth?.clk_mode }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td rowspan="6">Display</td>
|
||||||
|
<td>type</td>
|
||||||
|
<td>{{ selectedPinAssignment?.display?.type }}</td>
|
||||||
|
<td>{{ currentPinAssignment?.display?.type }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>data</td>
|
||||||
|
<td>{{ selectedPinAssignment?.display?.data }}</td>
|
||||||
|
<td>{{ currentPinAssignment?.display?.data }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>clk</td>
|
||||||
|
<td>{{ selectedPinAssignment?.display?.clk }}</td>
|
||||||
|
<td>{{ currentPinAssignment?.display?.clk }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>cs</td>
|
||||||
|
<td>{{ selectedPinAssignment?.display?.cs }}</td>
|
||||||
|
<td>{{ currentPinAssignment?.display?.cs }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>reset</td>
|
||||||
|
<td>{{ selectedPinAssignment?.display?.reset }}</td>
|
||||||
|
<td>{{ currentPinAssignment?.display?.reset }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -493,7 +493,7 @@
|
|||||||
"Back": "Zurück",
|
"Back": "Zurück",
|
||||||
"Retry": "Wiederholen",
|
"Retry": "Wiederholen",
|
||||||
"OtaStatus": "OTA Status",
|
"OtaStatus": "OTA Status",
|
||||||
"OtaSuccess": "OTA Erfolgreich. Das Gerät wurde automatisch neu gestartet und wird in wenigen Augenblicken wieder zur Verfügung stehen.",
|
"OtaSuccess": "OTA Erfolgreich. Das Gerät wurde automatisch neu gestartet und wird in wenigen Augenblicken wieder zur Verfügung stehen. Bitte nicht vergessen die Weboberfläche neu zu laden!",
|
||||||
"FirmwareUpload": "Firmware hochladen",
|
"FirmwareUpload": "Firmware hochladen",
|
||||||
"UploadProgress": "Hochlade Fortschritt"
|
"UploadProgress": "Hochlade Fortschritt"
|
||||||
},
|
},
|
||||||
@ -524,6 +524,13 @@
|
|||||||
"SelectedProfile": "Ausgewähltes Profil:",
|
"SelectedProfile": "Ausgewähltes Profil:",
|
||||||
"DefaultProfile": "(Standard Einstellungen)",
|
"DefaultProfile": "(Standard Einstellungen)",
|
||||||
"ProfileHint": "Ihr Gerät reagiert möglicherweise nicht mehr, wenn Sie ein inkompatibles Profil wählen. In diesem Fall müssen Sie eine Löschung über das serielle Interface durchführen.",
|
"ProfileHint": "Ihr Gerät reagiert möglicherweise nicht mehr, wenn Sie ein inkompatibles Profil wählen. In diesem Fall müssen Sie eine Löschung über das serielle Interface durchführen.",
|
||||||
|
"Display": "Display",
|
||||||
|
"PowerSafe": "Power Safe aktivieren:",
|
||||||
|
"PowerSafeHint": "Schaltet das Display aus wenn kein Wechselrichter produziert",
|
||||||
|
"Screensaver": "Screensaver aktivieren:",
|
||||||
|
"ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern. (Nützlich v.a. für OLED Displays)",
|
||||||
|
"ShowLogo": "Logo anzeigen:",
|
||||||
|
"Contrast": "Kontrast ({contrast}):",
|
||||||
"Save": "@:dtuadmin.Save"
|
"Save": "@:dtuadmin.Save"
|
||||||
},
|
},
|
||||||
"pininfo": {
|
"pininfo": {
|
||||||
|
|||||||
@ -493,7 +493,7 @@
|
|||||||
"Back": "Back",
|
"Back": "Back",
|
||||||
"Retry": "Retry",
|
"Retry": "Retry",
|
||||||
"OtaStatus": "OTA Status",
|
"OtaStatus": "OTA Status",
|
||||||
"OtaSuccess": "OTA Success. The unit has been automatically restarted and will be available again in a few moments.",
|
"OtaSuccess": "OTA Success. The unit has been automatically restarted and will be available again in a few moments. Please do not forget to reload the web interface!",
|
||||||
"FirmwareUpload": "Firmware Upload",
|
"FirmwareUpload": "Firmware Upload",
|
||||||
"UploadProgress": "Upload Progress"
|
"UploadProgress": "Upload Progress"
|
||||||
},
|
},
|
||||||
@ -524,6 +524,13 @@
|
|||||||
"SelectedProfile": "Selected profile:",
|
"SelectedProfile": "Selected profile:",
|
||||||
"DefaultProfile": "(Default settings)",
|
"DefaultProfile": "(Default settings)",
|
||||||
"ProfileHint": "Your device may stop responding if you select an incompatible profile. In this case, you must perform a deletion via the serial interface.",
|
"ProfileHint": "Your device may stop responding if you select an incompatible profile. In this case, you must perform a deletion via the serial interface.",
|
||||||
|
"Display": "Display",
|
||||||
|
"PowerSafe": "Enable Power Safe:",
|
||||||
|
"PowerSafeHint": "Turn off the display if no inverter is producing.",
|
||||||
|
"Screensaver": "Enable Screensaver:",
|
||||||
|
"ScreensaverHint": "Move the display a little bit on each update to prevent burn-in. (Useful especially for OLED displays)",
|
||||||
|
"ShowLogo": "Show Logo:",
|
||||||
|
"Contrast": "Contrast ({contrast}):",
|
||||||
"Save": "@:dtuadmin.Save"
|
"Save": "@:dtuadmin.Save"
|
||||||
},
|
},
|
||||||
"pininfo": {
|
"pininfo": {
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
"InverterSettings": "Paramètres des onduleurs",
|
"InverterSettings": "Paramètres des onduleurs",
|
||||||
"SecuritySettings": "Paramètres de sécurité",
|
"SecuritySettings": "Paramètres de sécurité",
|
||||||
"DTUSettings": "Paramètres DTU",
|
"DTUSettings": "Paramètres DTU",
|
||||||
"DeviceManager": "Device-Manager",
|
"DeviceManager": "Gestionnaire de périphériques",
|
||||||
"VedirectSettings": "Paramètres Ve.direct",
|
"VedirectSettings": "Paramètres Ve.direct",
|
||||||
"ConfigManagement": "Gestion de la configuration",
|
"ConfigManagement": "Gestion de la configuration",
|
||||||
"FirmwareUpgrade": "Mise à jour du firmware",
|
"FirmwareUpgrade": "Mise à jour du firmware",
|
||||||
@ -86,7 +86,7 @@
|
|||||||
"10002": "Authentification réussie !",
|
"10002": "Authentification réussie !",
|
||||||
"11001": "@:apiresponse.2001",
|
"11001": "@:apiresponse.2001",
|
||||||
"11002": "@:apiresponse:5004",
|
"11002": "@:apiresponse:5004",
|
||||||
"12001": "Profil must between 1 and {max} characters long!"
|
"12001": "Le profil doit comporter entre 1 et {max} caractères !"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
"LiveData": "Données en direct",
|
"LiveData": "Données en direct",
|
||||||
@ -493,7 +493,7 @@
|
|||||||
"Back": "Retour",
|
"Back": "Retour",
|
||||||
"Retry": "Réessayer",
|
"Retry": "Réessayer",
|
||||||
"OtaStatus": "Statut OTA",
|
"OtaStatus": "Statut OTA",
|
||||||
"OtaSuccess": "Succès de l'OTA. L'unité a été automatiquement redémarrée et sera à nouveau disponible dans quelques instants.",
|
"OtaSuccess": "Succès de l'OTA. L'unité a été automatiquement redémarrée et sera à nouveau disponible dans quelques instants. N'oubliez pas de recharger l'interface web !",
|
||||||
"FirmwareUpload": "Téléversement du firmware",
|
"FirmwareUpload": "Téléversement du firmware",
|
||||||
"UploadProgress": "Progression du téléversement"
|
"UploadProgress": "Progression du téléversement"
|
||||||
},
|
},
|
||||||
@ -519,18 +519,25 @@
|
|||||||
"DefaultPasswordLink": "Merci de changer le mot de passe."
|
"DefaultPasswordLink": "Merci de changer le mot de passe."
|
||||||
},
|
},
|
||||||
"deviceadmin": {
|
"deviceadmin": {
|
||||||
"DeviceManager": "Device-Manager",
|
"DeviceManager": "Gestionnaire de périphériques",
|
||||||
"PinAssignment": "Connection settings",
|
"PinAssignment": "Paramètres de connexion",
|
||||||
"SelectedProfile": "Selected profile:",
|
"SelectedProfile": "Profil sélectionné",
|
||||||
"DefaultProfile": "(Default settings)",
|
"DefaultProfile": "(Réglages par défaut)",
|
||||||
"ProfileHint": "Your device may stop responding if you select an incompatible profile. In this case, you must perform a deletion via the serial interface.",
|
"ProfileHint": "Votre appareil peut cesser de répondre si vous sélectionnez un profil incompatible. Dans ce cas, vous devez effectuer une suppression via l'interface série.",
|
||||||
|
"Display": "Affichage",
|
||||||
|
"PowerSafe": "Activer l'économiseur d'énergie",
|
||||||
|
"PowerSafeHint": "Eteindre l'écran si aucun onduleur n'est en production.",
|
||||||
|
"Screensaver": "Activer l'écran de veille",
|
||||||
|
"ScreensaverHint": "Déplacez un peu l'écran à chaque mise à jour pour éviter le phénomène de brûlure. (Utile surtout pour les écrans OLED)",
|
||||||
|
"ShowLogo": "Afficher le logo",
|
||||||
|
"Contrast": "Contraste ({contrast}):",
|
||||||
"Save": "@:dtuadmin.Save"
|
"Save": "@:dtuadmin.Save"
|
||||||
},
|
},
|
||||||
"pininfo": {
|
"pininfo": {
|
||||||
"PinOverview": "Connection overview",
|
"PinOverview": "Vue d'ensemble des connexions",
|
||||||
"Category": "Category",
|
"Category": "Catégorie",
|
||||||
"Name": "Name",
|
"Name": "Nom",
|
||||||
"ValueSelected": "Selected",
|
"ValueSelected": "Sélectionné",
|
||||||
"ValueActive": "Active"
|
"ValueActive": "Activé"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,5 +1,13 @@
|
|||||||
import type { Device } from "./PinMapping";
|
import type { Device } from "./PinMapping";
|
||||||
|
|
||||||
|
export interface Display {
|
||||||
|
show_logo: boolean;
|
||||||
|
power_safe: boolean;
|
||||||
|
screensaver: boolean;
|
||||||
|
contrast: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DeviceConfig {
|
export interface DeviceConfig {
|
||||||
curPin: Device;
|
curPin: Device;
|
||||||
|
display: Display;
|
||||||
}
|
}
|
||||||
@ -17,10 +17,19 @@ export interface Ethernet {
|
|||||||
clk_mode: number;
|
clk_mode: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Display {
|
||||||
|
type: number;
|
||||||
|
data: number;
|
||||||
|
clk: number;
|
||||||
|
cs: number;
|
||||||
|
reset: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Device {
|
export interface Device {
|
||||||
name: string;
|
name: string;
|
||||||
nrf24: Nrf24;
|
nrf24: Nrf24;
|
||||||
eth: Ethernet;
|
eth: Ethernet;
|
||||||
|
display: Display;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PinMapping extends Array<Device>{}
|
export interface PinMapping extends Array<Device>{}
|
||||||
@ -4,12 +4,15 @@
|
|||||||
{{ alertMessage }}
|
{{ alertMessage }}
|
||||||
</BootstrapAlert>
|
</BootstrapAlert>
|
||||||
|
|
||||||
|
<form @submit="savePinConfig">
|
||||||
<nav>
|
<nav>
|
||||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||||
<button class="nav-link active" id="nav-pin-tab" data-bs-toggle="tab" data-bs-target="#nav-pin"
|
<button class="nav-link active" id="nav-pin-tab" data-bs-toggle="tab" data-bs-target="#nav-pin"
|
||||||
type="button" role="tab" aria-controls="nav-pin" aria-selected="true">{{
|
type="button" role="tab" aria-controls="nav-pin" aria-selected="true">{{
|
||||||
$t('deviceadmin.PinAssignment')
|
$t('deviceadmin.PinAssignment')
|
||||||
}}</button>
|
}}</button>
|
||||||
|
<button class="nav-link" id="nav-display-tab" data-bs-toggle="tab" data-bs-target="#nav-display"
|
||||||
|
type="button" role="tab" aria-controls="nav-display">{{ $t('deviceadmin.Display') }}</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="tab-content" id="nav-tabContent">
|
<div class="tab-content" id="nav-tabContent">
|
||||||
@ -17,8 +20,6 @@
|
|||||||
tabindex="0">
|
tabindex="0">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<form @submit="savePinConfig">
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="inputPinProfile" class="col-sm-2 col-form-label">{{
|
<label for="inputPinProfile" class="col-sm-2 col-form-label">{{
|
||||||
$t('deviceadmin.SelectedProfile')
|
$t('deviceadmin.SelectedProfile')
|
||||||
@ -26,7 +27,8 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<select class="form-select" id="inputPinProfile"
|
<select class="form-select" id="inputPinProfile"
|
||||||
v-model="deviceConfigList.curPin.name">
|
v-model="deviceConfigList.curPin.name">
|
||||||
<option v-for="device in pinMappingList" :value="device.name" :key="device.name">
|
<option v-for="device in pinMappingList" :value="device.name"
|
||||||
|
:key="device.name">
|
||||||
{{ device.name }}
|
{{ device.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
@ -39,21 +41,51 @@
|
|||||||
<PinInfo
|
<PinInfo
|
||||||
:selectedPinAssignment="pinMappingList.find(i => i.name === deviceConfigList.curPin.name)"
|
:selectedPinAssignment="pinMappingList.find(i => i.name === deviceConfigList.curPin.name)"
|
||||||
:currentPinAssignment="deviceConfigList.curPin" />
|
:currentPinAssignment="deviceConfigList.curPin" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-pane fade show" id="nav-display" role="tabpanel" aria-labelledby="nav-display-tab"
|
||||||
|
tabindex="0">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<InputElement :label="$t('deviceadmin.PowerSafe')"
|
||||||
|
v-model="deviceConfigList.display.power_safe" type="checkbox"
|
||||||
|
:tooltip="$t('deviceadmin.PowerSafeHint')" />
|
||||||
|
|
||||||
|
<InputElement :label="$t('deviceadmin.Screensaver')"
|
||||||
|
v-model="deviceConfigList.display.screensaver" type="checkbox"
|
||||||
|
:tooltip="$t('deviceadmin.ScreensaverHint')" />
|
||||||
|
|
||||||
|
<InputElement :label="$t('deviceadmin.ShowLogo')"
|
||||||
|
v-model="deviceConfigList.display.show_logo" type="checkbox" />
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="inputDisplayContrast" class="col-sm-2 col-form-label">{{
|
||||||
|
$t('deviceadmin.Contrast', { contrast: $n(deviceConfigList.display.contrast / 100,
|
||||||
|
'percent')
|
||||||
|
}) }}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="range" class="form-range" min="0" max="100" id="inputDisplayContrast"
|
||||||
|
v-model="deviceConfigList.display.contrast" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary mb-3">{{ $t('deviceadmin.Save') }}</button>
|
<button type="submit" class="btn btn-primary mb-3">{{ $t('deviceadmin.Save') }}</button>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</BasePage>
|
</BasePage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import BasePage from '@/components/BasePage.vue';
|
import BasePage from '@/components/BasePage.vue';
|
||||||
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
||||||
|
import InputElement from '@/components/InputElement.vue';
|
||||||
import PinInfo from '@/components/PinInfo.vue';
|
import PinInfo from '@/components/PinInfo.vue';
|
||||||
import type { DeviceConfig } from "@/types/DeviceConfig";
|
import type { DeviceConfig } from "@/types/DeviceConfig";
|
||||||
import type { PinMapping, Device } from "@/types/PinMapping";
|
import type { PinMapping, Device } from "@/types/PinMapping";
|
||||||
@ -64,6 +96,7 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
BasePage,
|
BasePage,
|
||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
|
InputElement,
|
||||||
PinInfo,
|
PinInfo,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|||||||