├── .gitignore ├── docs ├── Elster-IN-Z61.jpg ├── Gas-Verbrauch.png ├── Gasverbrauch-heute.png ├── esp32-gaszaehler.jpg ├── ESP32-Z61-Gaszaehler.jpg ├── Sensor-Gasverbrauch.png ├── Dashboard-Gasverbrauch.png ├── Gasverbrauch-pro-Stunde.png └── Gasverbrauch-letze-Woche.png ├── README.md ├── common ├── base_webserver.yaml ├── secrets.yaml ├── base.yaml └── base_global.yaml ├── LICENSE ├── _static ├── webserver-v1.min.js ├── webserver-v1.js ├── webserver-v1.min.css └── webserver-v1.css ├── gasmeter.yaml └── wasserundgas.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /docs/Elster-IN-Z61.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Elster-IN-Z61.jpg -------------------------------------------------------------------------------- /docs/Gas-Verbrauch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Gas-Verbrauch.png -------------------------------------------------------------------------------- /docs/Gasverbrauch-heute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Gasverbrauch-heute.png -------------------------------------------------------------------------------- /docs/esp32-gaszaehler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/esp32-gaszaehler.jpg -------------------------------------------------------------------------------- /docs/ESP32-Z61-Gaszaehler.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/ESP32-Z61-Gaszaehler.jpg -------------------------------------------------------------------------------- /docs/Sensor-Gasverbrauch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Sensor-Gasverbrauch.png -------------------------------------------------------------------------------- /docs/Dashboard-Gasverbrauch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Dashboard-Gasverbrauch.png -------------------------------------------------------------------------------- /docs/Gasverbrauch-pro-Stunde.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Gasverbrauch-pro-Stunde.png -------------------------------------------------------------------------------- /docs/Gasverbrauch-letze-Woche.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zibous/ha-gasmeter/HEAD/docs/Gasverbrauch-letze-Woche.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ha-gasmeter 2 | Reads gasmeter 3 | 4 | 5 | 6 | 7 | 8 | ![gasmeter](./docs/Elster-IN-Z61.jpg) 9 | 10 | 11 | 12 | ## NODEMCU Modul 13 | 14 | ![ESP32](./docs/ESP32-Z61-Gaszaehler.jpg) 15 | 16 | -------------------------------------------------------------------------------- /common/base_webserver.yaml: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------- 2 | ## WEBSERVER Settings 3 | ## --------------------------------------------------- 4 | web_server: 5 | port: 80 6 | css_include: "_static/webserver-v1.min.css" 7 | css_url: "" 8 | js_include: "_static/webserver-v1.min.js" 9 | js_url: "" -------------------------------------------------------------------------------- /common/secrets.yaml: -------------------------------------------------------------------------------- 1 | ## Example of the settings, before creating the 2 | ## application adjust it for your environment. 3 | 4 | ssid1_pswd: "UpdJyFeHQUrwmM8bbs" 5 | ssid1_name: "Wlanrouter1" 6 | 7 | ssid2_pswd: "fxRGjE2aiL6PCd9caK" 8 | ssid2_name: "Wlanrouter2" 9 | 10 | domain: ".lab.home" 11 | 12 | app_pswd: "pzW8z8jE9XSXyDo9Ng" 13 | ota_pswd: "7wnRTacNf9jm5DNKWC" 14 | ha_pswd: "7wnRTacNf9jm5DNKWC" 15 | 16 | mqtt_broker: mqtt_broker.local 17 | mqtt_username: webservice 18 | mqtt_password: hxt3Xw5jYJZuUvscLi 19 | 20 | home_latitude: 47.4581049 21 | home_longitude: 9.6371659 22 | home_elevation: 403 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Peter Siebler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /_static/webserver-v1.min.js: -------------------------------------------------------------------------------- 1 | const source=new EventSource("/events");source.addEventListener('log',function(e){const log=document.getElementById("log");let klass='';if(e.data.startsWith("")){klass='e';}else if(e.data.startsWith("")){klass='w';}else if(e.data.startsWith("")){klass='i';}else if(e.data.startsWith("")){klass='c';}else if(e.data.startsWith("")){klass='d';}else if(e.data.startsWith("")){klass='v';}else{log.innerHTML+=e.data+'\n';} 2 | log.innerHTML+=''+e.data.substr(7,e.data.length-10)+"\n";});source.addEventListener('state',function(e){const data=JSON.parse(e.data);document.getElementById(data.id).children[1].innerText=data.state;});const states=document.getElementById("states");let i=0,row;for(;row=states.rows[i];i++){if(!row.children[2].children.length){continue;} 3 | if(row.classList.contains("switch")){(function(id){row.children[2].children[0].addEventListener('click',function(){const xhr=new XMLHttpRequest();xhr.open("POST",'/switch/'+id.substr(7)+'/toggle',true);xhr.send();});})(row.id);} 4 | if(row.classList.contains("fan")){(function(id){row.children[2].children[0].addEventListener('click',function(){const xhr=new XMLHttpRequest();xhr.open("POST",'/fan/'+id.substr(4)+'/toggle',true);xhr.send();});})(row.id);} 5 | if(row.classList.contains("light")){(function(id){row.children[2].children[0].addEventListener('click',function(){const xhr=new XMLHttpRequest();xhr.open("POST",'/light/'+id.substr(6)+'/toggle',true);xhr.send();});})(row.id);} 6 | if(row.classList.contains("cover")){(function(id){row.children[2].children[0].addEventListener('click',function(){const xhr=new XMLHttpRequest();xhr.open("POST",'/cover/'+id.substr(6)+'/open',true);xhr.send();});row.children[2].children[1].addEventListener('click',function(){const xhr=new XMLHttpRequest();xhr.open("POST",'/cover/'+id.substr(6)+'/close',true);xhr.send();});})(row.id);} 7 | if(row.classList.contains("select")){(function(id){row.children[2].children[0].addEventListener('change',function(){const xhr=new XMLHttpRequest();xhr.open("POST",'/select/'+id.substr(7)+'/set?option='+encodeURIComponent(this.value),true);xhr.send();});})(row.id);}} -------------------------------------------------------------------------------- /_static/webserver-v1.js: -------------------------------------------------------------------------------- 1 | const source = new EventSource("/events"); 2 | 3 | source.addEventListener('log', function (e) { 4 | const log = document.getElementById("log"); 5 | let klass = ''; 6 | if (e.data.startsWith("")) { 7 | klass = 'e'; 8 | } else if (e.data.startsWith("")) { 9 | klass = 'w'; 10 | } else if (e.data.startsWith("")) { 11 | klass = 'i'; 12 | } else if (e.data.startsWith("")) { 13 | klass = 'c'; 14 | } else if (e.data.startsWith("")) { 15 | klass = 'd'; 16 | } else if (e.data.startsWith("")) { 17 | klass = 'v'; 18 | } else { 19 | log.innerHTML += e.data + '\n'; 20 | } 21 | log.innerHTML += '' + e.data.substr(7, e.data.length - 10) + "\n"; 22 | }); 23 | 24 | source.addEventListener('state', function (e) { 25 | const data = JSON.parse(e.data); 26 | document.getElementById(data.id).children[1].innerText = data.state; 27 | }); 28 | 29 | const states = document.getElementById("states"); 30 | let i = 0, row; 31 | for (; row = states.rows[i]; i++) { 32 | if (!row.children[2].children.length) { 33 | continue; 34 | } 35 | 36 | if (row.classList.contains("switch")) { 37 | (function(id) { 38 | row.children[2].children[0].addEventListener('click', function () { 39 | const xhr = new XMLHttpRequest(); 40 | xhr.open("POST", '/switch/' + id.substr(7) + '/toggle', true); 41 | xhr.send(); 42 | }); 43 | })(row.id); 44 | } 45 | if (row.classList.contains("fan")) { 46 | (function(id) { 47 | row.children[2].children[0].addEventListener('click', function () { 48 | const xhr = new XMLHttpRequest(); 49 | xhr.open("POST", '/fan/' + id.substr(4) + '/toggle', true); 50 | xhr.send(); 51 | }); 52 | })(row.id); 53 | } 54 | if (row.classList.contains("light")) { 55 | (function(id) { 56 | row.children[2].children[0].addEventListener('click', function () { 57 | const xhr = new XMLHttpRequest(); 58 | xhr.open("POST", '/light/' + id.substr(6) + '/toggle', true); 59 | xhr.send(); 60 | }); 61 | })(row.id); 62 | } 63 | if (row.classList.contains("cover")) { 64 | (function(id) { 65 | row.children[2].children[0].addEventListener('click', function () { 66 | const xhr = new XMLHttpRequest(); 67 | xhr.open("POST", '/cover/' + id.substr(6) + '/open', true); 68 | xhr.send(); 69 | }); 70 | row.children[2].children[1].addEventListener('click', function () { 71 | const xhr = new XMLHttpRequest(); 72 | xhr.open("POST", '/cover/' + id.substr(6) + '/close', true); 73 | xhr.send(); 74 | }); 75 | })(row.id); 76 | } 77 | if (row.classList.contains("select")) { 78 | (function(id) { 79 | row.children[2].children[0].addEventListener('change', function () { 80 | const xhr = new XMLHttpRequest(); 81 | xhr.open("POST", '/select/' + id.substr(7) + '/set?option=' + encodeURIComponent(this.value), true); 82 | xhr.send(); 83 | }); 84 | })(row.id); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /common/base.yaml: -------------------------------------------------------------------------------- 1 | # Base Configuration the selected device 2 | # Valid for esp32 and esp8266 w/o BLE SCANNER 3 | # 4 | # Used substitutions: 5 | # 6 | # - device_name_short: Hostname for the device 7 | # - platform: used platform 8 | # - board: used board 9 | # - node_name: name of the device 10 | # - secret file for all private settings 11 | # 12 | # Setup for: 13 | # 14 | # - WIFI 15 | # - WEBSERVER 16 | # - LOGGER 17 | # - OTA 18 | # - Time server 19 | # - API Homeassistant 20 | # - BLE TRACKER 21 | # - Globals for bootcounter, daily value 22 | # 23 | # Sensors: 24 | # - binary_sensor status 25 | # - switch restart 26 | # - switch reset boot counter 27 | # - sensor Boot counter 28 | # - sensor uptime 29 | # - sensor wifi_signal 30 | # - text_sensor version 31 | # - text_sensor Online seit 32 | # - text_sensor IP address 33 | # - text_sensor SSID Name 34 | # - text_sensor BSSID 35 | # - text_sensor Current Timestamp 36 | 37 | 38 | # substitutions: 39 | # update_interval: 60s 40 | 41 | esphome: 42 | name: ${device_name_short} 43 | build_path: ./build/${device_name_short} 44 | on_boot: 45 | then: 46 | - logger.log: 47 | level: info 48 | format: "BOOTMESSAGE:${device_name_short} API is connected, Device ready!" 49 | - globals.set: 50 | id: boot_counter 51 | value: !lambda "return id(boot_counter)+=1;" 52 | on_shutdown: 53 | then: 54 | - logger.log: ${device_name_short} is down! 55 | 56 | ## --------------------------------------------------- 57 | ## WIFI Settings 58 | ## --------------------------------------------------- 59 | wifi: 60 | use_address: ${device_name_short}.local 61 | networks: 62 | - ssid: !secret ssid1_name 63 | password: !secret ssid1_pswd 64 | - ssid: !secret ssid2_name 65 | password: !secret ssid2_pswd 66 | 67 | ## --------------------------------------------------- 68 | ## WEBSERVER Settings 69 | ## --------------------------------------------------- 70 | web_server: 71 | port: 80 72 | css_include: "_static/webserver-v1.min.css" 73 | css_url: "" 74 | js_include: "_static/webserver-v1.min.js" 75 | js_url: "" 76 | 77 | ## --------------------------------------------------- 78 | ## Enable logging 79 | ## --------------------------------------------------- 80 | logger: 81 | 82 | ## --------------------------------------------------- 83 | ## OTA Settings 84 | ## --------------------------------------------------- 85 | ota: 86 | password: !secret ota_pswd 87 | on_error: 88 | then: 89 | - logger.log: 90 | format: "OTA update error %d" 91 | args: ["x"] 92 | 93 | # ---------------------------------------------------------------- 94 | # Native API Component 95 | # ---------------------------------------------------------------- 96 | api: 97 | id: espapi 98 | port: 6053 99 | reboot_timeout: 5min 100 | 101 | ## --------------------------------------------------- 102 | ## SNTP Time server 103 | ## --------------------------------------------------- 104 | time: 105 | - platform: sntp 106 | id: sntp_time 107 | timezone: Europe/Berlin 108 | servers: 109 | - 0.at.pool.ntp.org 110 | - 0.pool.ntp.org 111 | - 1.pool.ntp.org 112 | on_time: 113 | - seconds: 0 114 | minutes: 0 115 | hours: 0 116 | then: 117 | - lambda: |- 118 | if(id(daily_value)){ 119 | id(daily_value)=0.00; 120 | } 121 | - seconds: 0 122 | minutes: 0 123 | then: 124 | - lambda: |- 125 | if(id(hour_value)){ 126 | id(hour_value)=0.00; 127 | } 128 | on_time_sync: 129 | then: 130 | - logger.log: "Synchronized sntp clock" 131 | 132 | -------------------------------------------------------------------------------- /common/base_global.yaml: -------------------------------------------------------------------------------- 1 | 2 | # ---------------------------------------------------------------- 3 | # Global variables 4 | # ---------------------------------------------------------------- 5 | globals: 6 | - id: boot_counter 7 | type: int 8 | restore_value: yes 9 | initial_value: "0" 10 | - id: daily_value 11 | type: float 12 | restore_value: yes 13 | initial_value: "0.0" 14 | - id: hour_value 15 | type: float 16 | restore_value: yes 17 | initial_value: "0.0" 18 | 19 | ## --------------------------------------------------- 20 | ## binary sensors 21 | ## --------------------------------------------------- 22 | binary_sensor: 23 | - platform: status 24 | name: ${friendly_name} Status 25 | 26 | ## --------------------------------------------------- 27 | ## switches 28 | ## --------------------------------------------------- 29 | switch: 30 | - platform: restart 31 | id: restart_device 32 | name: ${friendly_name} restart 33 | - platform: template 34 | name: ${friendly_name} reset boot counter 35 | turn_on_action: 36 | then: 37 | - lambda: |- 38 | id(boot_counter) = 0; 39 | id(bootcounter).update(); 40 | - logger.log: ${device_name_short} reset boot counter o.k! 41 | 42 | ## --------------------------------------------------- 43 | ## all default sensors 44 | ## --------------------------------------------------- 45 | sensor: 46 | 47 | - platform: template 48 | name: ${friendly_name} Boot counter 49 | id: bootcounter 50 | accuracy_decimals: 0 51 | lambda: |- 52 | return (id(boot_counter)); 53 | 54 | - platform: uptime 55 | name: ${friendly_name} Uptime Sensor 56 | id: uptime_sensor 57 | update_interval: ${update_interval} 58 | on_raw_value: 59 | then: 60 | - text_sensor.template.publish: 61 | id: uptime_human 62 | state: !lambda |- 63 | int seconds = round(id(uptime_sensor).raw_state); 64 | int days = seconds / (24 * 3600); 65 | seconds = seconds % (24 * 3600); 66 | int hours = seconds / 3600; 67 | seconds = seconds % 3600; 68 | int minutes = seconds / 60; 69 | seconds = seconds % 60; 70 | return ( 71 | (days ? String(days) + "d " : "") + 72 | (hours ? String(hours) + "h " : "") + 73 | (minutes ? String(minutes) + "m " : "") + 74 | (String(seconds) + "s") 75 | ).c_str(); 76 | 77 | - platform: wifi_signal 78 | id: wifisignal 79 | name: ${friendly_name} WiFi Signal 80 | update_interval: 60s 81 | 82 | - platform: template 83 | id: sensor_wifi_signal_percentage 84 | name: "${friendly_name} WiFi Signal Percentage" 85 | icon: "mdi:wifi" 86 | unit_of_measurement: "%" 87 | update_interval: 60s 88 | lambda: |- 89 | if (id(wifisignal).state) { 90 | if (id(wifisignal).state <= -100 ) { 91 | return 0; 92 | } else if (id(wifisignal).state >= -50) { 93 | return 100; 94 | } else { 95 | return 2 * (id(wifisignal).state + 100); 96 | } 97 | } else { 98 | return NAN; 99 | } 100 | 101 | 102 | ## --------------------------------------------------- 103 | ## all text sensors 104 | ## --------------------------------------------------- 105 | text_sensor: 106 | - platform: version 107 | name: ${friendly_name} Version 108 | id: appver 109 | 110 | - platform: template 111 | name: ${friendly_name} Online seit 112 | id: uptime_human 113 | icon: mdi:clock-start 114 | 115 | - platform: wifi_info 116 | ip_address: 117 | name: ${friendly_name} IP 118 | id: wifiip 119 | icon: mdi:ip-network 120 | 121 | ssid: 122 | name: ${friendly_name} SSID 123 | id: wifiip_ssid 124 | icon: mdi:wifi 125 | 126 | bssid: 127 | name: ${friendly_name} BSSID 128 | id: wifiip_bssid 129 | icon: mdi:wifi 130 | 131 | mac_address: 132 | name: ${friendly_name} Mac Wifi Address 133 | id: wifimac_address 134 | icon: mdi:wifi 135 | 136 | - platform: template 137 | name: ${friendly_name} Timestamp 138 | id: systime 139 | lambda: char str[20]; 140 | time_t currTime = id(sntp_time).now().timestamp; 141 | strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%S", localtime(&currTime)); 142 | return (std::string) str; 143 | -------------------------------------------------------------------------------- /_static/webserver-v1.min.css: -------------------------------------------------------------------------------- 1 | /* Based off of https://github.com/sindresorhus/github-markdown-css */ 2 | .markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;line-height:1.5;color:#24292e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body a{background-color:transparent}.markdown-body a:active,.markdown-body a:hover{outline-width:0}.markdown-body strong{font-weight:bolder}.markdown-body h1{font-size:2em;margin:0.67em 0}.markdown-body img{border-style:none}.markdown-body pre{font-family:monospace,monospace;font-size:1em}.markdown-body hr{box-sizing:content-box;height:0;overflow:visible}.markdown-body input{font:inherit;margin:0}.markdown-body input{overflow:visible}.markdown-body [type="checkbox"]{box-sizing:border-box;padding:0}.markdown-body *{box-sizing:border-box}.markdown-body input{font-family:inherit;font-size:inherit;line-height:inherit}.markdown-body a{color:#0366d6;text-decoration:none}.markdown-body a:hover{text-decoration:underline}.markdown-body strong{font-weight:600}.markdown-body hr{height:0;margin:15px 0;overflow:hidden;background:transparent;border:0;border-bottom:1px solid #dfe2e5}.markdown-body hr::before{display:table;content:""}.markdown-body hr::after{display:table;clear:both;content:""}.markdown-body table{border-spacing:0;border-collapse:collapse}.markdown-body td,.markdown-body th{padding:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:0;margin-bottom:0}.markdown-body h1{font-size:32px;font-weight:600}.markdown-body h2{font-size:24px;font-weight:600}.markdown-body h3{font-size:20px;font-weight:600}.markdown-body h4{font-size:16px;font-weight:600}.markdown-body h5{font-size:14px;font-weight:600}.markdown-body h6{font-size:12px;font-weight:600}.markdown-body p{margin-top:0;margin-bottom:10px}.markdown-body blockquote{margin:0}.markdown-body ul,.markdown-body ol{padding-left:0;margin-top:0;margin-bottom:0}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ul ul ol,.markdown-body ul ol ol,.markdown-body ol ul ol,.markdown-body ol ol ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body pre{margin-top:0;margin-bottom:0;font-family:"SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:12px}.markdown-body::before{display:table;content:""}.markdown-body::after{display:table;clear:both;content:""}.markdown-body>*:first-child{margin-top:0!important}.markdown-body>*:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body p,.markdown-body blockquote,.markdown-body ul,.markdown-body ol,.markdown-body dl,.markdown-body table,.markdown-body pre{margin-top:0;margin-bottom:16px}.markdown-body hr{height:0.25em;padding:0;margin:24px 0;background-color:#e1e4e8;border:0}.markdown-body blockquote{padding:0 1em;color:#6a737d;border-left:0.25em solid #dfe2e5}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}.markdown-body h1{padding-bottom:0.3em;font-size:2em;border-bottom:1px solid #eaecef}.markdown-body h2{padding-bottom:0.3em;font-size:1.5em;border-bottom:1px solid #eaecef}.markdown-body h3{font-size:1.25em}.markdown-body h4{font-size:1em}.markdown-body h5{font-size:0.875em}.markdown-body h6{font-size:0.85em;color:#6a737d}.markdown-body ul,.markdown-body ol{padding-left:2em}.markdown-body ul ul,.markdown-body ul ol,.markdown-body ol ol,.markdown-body ol ul{margin-top:0;margin-bottom:0}.markdown-body li{word-wrap:break-all}.markdown-body li>p{margin-top:16px}.markdown-body li+li{margin-top:0.25em}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:600}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body table{display:block;width:100%;overflow:auto}.markdown-body table th{font-weight:600}.markdown-body table th,.markdown-body table td{padding:6px 13px;border:1px solid #dfe2e5}.markdown-body table tr{background-color:#fff;border-top:1px solid #c6cbd1}.markdown-body table tr:nth-child(2n){background-color:#f6f8fa}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f6f8fa;border-radius:3px;word-wrap:normal}.markdown-body:checked+.radio-label{position:relative;z-index:1;border-color:#0366d6}.markdown-body hr{border-bottom-color:#eee}#log .v{color:#888}#log .d{color:#0DD}#log .c{color:magenta}#log .i{color:limegreen}#log .w{color:yellow}#log .e{color:red;font-weight:bold}#log{background-color:#1c1c1c} -------------------------------------------------------------------------------- /_static/webserver-v1.css: -------------------------------------------------------------------------------- 1 | /* Based off of https://github.com/sindresorhus/github-markdown-css */ 2 | 3 | .markdown-body { 4 | -ms-text-size-adjust: 100%; 5 | -webkit-text-size-adjust: 100%; 6 | line-height: 1.5; 7 | color: #24292e; 8 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 9 | font-size: 16px; 10 | word-wrap: break-word; 11 | } 12 | 13 | .markdown-body a { 14 | background-color: transparent; 15 | } 16 | 17 | .markdown-body a:active, 18 | .markdown-body a:hover { 19 | outline-width: 0; 20 | } 21 | 22 | .markdown-body strong { 23 | font-weight: bolder; 24 | } 25 | 26 | .markdown-body h1 { 27 | font-size: 2em; 28 | margin: 0.67em 0; 29 | } 30 | 31 | .markdown-body img { 32 | border-style: none; 33 | } 34 | 35 | .markdown-body pre { 36 | font-family: monospace, monospace; 37 | font-size: 1em; 38 | } 39 | 40 | .markdown-body hr { 41 | box-sizing: content-box; 42 | height: 0; 43 | overflow: visible; 44 | } 45 | 46 | .markdown-body input { 47 | font: inherit; 48 | margin: 0; 49 | } 50 | 51 | .markdown-body input { 52 | overflow: visible; 53 | } 54 | 55 | .markdown-body [type="checkbox"] { 56 | box-sizing: border-box; 57 | padding: 0; 58 | } 59 | 60 | .markdown-body * { 61 | box-sizing: border-box; 62 | } 63 | 64 | .markdown-body input { 65 | font-family: inherit; 66 | font-size: inherit; 67 | line-height: inherit; 68 | } 69 | 70 | .markdown-body a { 71 | color: #0366d6; 72 | text-decoration: none; 73 | } 74 | 75 | .markdown-body a:hover { 76 | text-decoration: underline; 77 | } 78 | 79 | .markdown-body strong { 80 | font-weight: 600; 81 | } 82 | 83 | .markdown-body hr { 84 | height: 0; 85 | margin: 15px 0; 86 | overflow: hidden; 87 | background: transparent; 88 | border: 0; 89 | border-bottom: 1px solid #dfe2e5; 90 | } 91 | 92 | .markdown-body hr::before { 93 | display: table; 94 | content: ""; 95 | } 96 | 97 | .markdown-body hr::after { 98 | display: table; 99 | clear: both; 100 | content: ""; 101 | } 102 | 103 | .markdown-body table { 104 | border-spacing: 0; 105 | border-collapse: collapse; 106 | } 107 | 108 | .markdown-body td, 109 | .markdown-body th { 110 | padding: 0; 111 | } 112 | 113 | .markdown-body h1, 114 | .markdown-body h2, 115 | .markdown-body h3, 116 | .markdown-body h4, 117 | .markdown-body h5, 118 | .markdown-body h6 { 119 | margin-top: 0; 120 | margin-bottom: 0; 121 | } 122 | 123 | .markdown-body h1 { 124 | font-size: 32px; 125 | font-weight: 600; 126 | } 127 | 128 | .markdown-body h2 { 129 | font-size: 24px; 130 | font-weight: 600; 131 | } 132 | 133 | .markdown-body h3 { 134 | font-size: 20px; 135 | font-weight: 600; 136 | } 137 | 138 | .markdown-body h4 { 139 | font-size: 16px; 140 | font-weight: 600; 141 | } 142 | 143 | .markdown-body h5 { 144 | font-size: 14px; 145 | font-weight: 600; 146 | } 147 | 148 | .markdown-body h6 { 149 | font-size: 12px; 150 | font-weight: 600; 151 | } 152 | 153 | .markdown-body p { 154 | margin-top: 0; 155 | margin-bottom: 10px; 156 | } 157 | 158 | .markdown-body blockquote { 159 | margin: 0; 160 | } 161 | 162 | .markdown-body ul, 163 | .markdown-body ol { 164 | padding-left: 0; 165 | margin-top: 0; 166 | margin-bottom: 0; 167 | } 168 | 169 | .markdown-body ol ol, 170 | .markdown-body ul ol { 171 | list-style-type: lower-roman; 172 | } 173 | 174 | .markdown-body ul ul ol, 175 | .markdown-body ul ol ol, 176 | .markdown-body ol ul ol, 177 | .markdown-body ol ol ol { 178 | list-style-type: lower-alpha; 179 | } 180 | 181 | .markdown-body dd { 182 | margin-left: 0; 183 | } 184 | 185 | .markdown-body pre { 186 | margin-top: 0; 187 | margin-bottom: 0; 188 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 189 | font-size: 12px; 190 | } 191 | .markdown-body::before { 192 | display: table; 193 | content: ""; 194 | } 195 | 196 | .markdown-body::after { 197 | display: table; 198 | clear: both; 199 | content: ""; 200 | } 201 | 202 | .markdown-body>*:first-child { 203 | margin-top: 0 !important; 204 | } 205 | 206 | .markdown-body>*:last-child { 207 | margin-bottom: 0 !important; 208 | } 209 | 210 | .markdown-body a:not([href]) { 211 | color: inherit; 212 | text-decoration: none; 213 | } 214 | 215 | .markdown-body p, 216 | .markdown-body blockquote, 217 | .markdown-body ul, 218 | .markdown-body ol, 219 | .markdown-body dl, 220 | .markdown-body table, 221 | .markdown-body pre { 222 | margin-top: 0; 223 | margin-bottom: 16px; 224 | } 225 | 226 | .markdown-body hr { 227 | height: 0.25em; 228 | padding: 0; 229 | margin: 24px 0; 230 | background-color: #e1e4e8; 231 | border: 0; 232 | } 233 | 234 | .markdown-body blockquote { 235 | padding: 0 1em; 236 | color: #6a737d; 237 | border-left: 0.25em solid #dfe2e5; 238 | } 239 | 240 | .markdown-body blockquote>:first-child { 241 | margin-top: 0; 242 | } 243 | 244 | .markdown-body blockquote>:last-child { 245 | margin-bottom: 0; 246 | } 247 | 248 | .markdown-body h1, 249 | .markdown-body h2, 250 | .markdown-body h3, 251 | .markdown-body h4, 252 | .markdown-body h5, 253 | .markdown-body h6 { 254 | margin-top: 24px; 255 | margin-bottom: 16px; 256 | font-weight: 600; 257 | line-height: 1.25; 258 | } 259 | 260 | .markdown-body h1 { 261 | padding-bottom: 0.3em; 262 | font-size: 2em; 263 | border-bottom: 1px solid #eaecef; 264 | } 265 | 266 | .markdown-body h2 { 267 | padding-bottom: 0.3em; 268 | font-size: 1.5em; 269 | border-bottom: 1px solid #eaecef; 270 | } 271 | 272 | .markdown-body h3 { 273 | font-size: 1.25em; 274 | } 275 | 276 | .markdown-body h4 { 277 | font-size: 1em; 278 | } 279 | 280 | .markdown-body h5 { 281 | font-size: 0.875em; 282 | } 283 | 284 | .markdown-body h6 { 285 | font-size: 0.85em; 286 | color: #6a737d; 287 | } 288 | 289 | .markdown-body ul, 290 | .markdown-body ol { 291 | padding-left: 2em; 292 | } 293 | 294 | .markdown-body ul ul, 295 | .markdown-body ul ol, 296 | .markdown-body ol ol, 297 | .markdown-body ol ul { 298 | margin-top: 0; 299 | margin-bottom: 0; 300 | } 301 | 302 | .markdown-body li { 303 | word-wrap: break-all; 304 | } 305 | 306 | .markdown-body li>p { 307 | margin-top: 16px; 308 | } 309 | 310 | .markdown-body li+li { 311 | margin-top: 0.25em; 312 | } 313 | 314 | .markdown-body dl { 315 | padding: 0; 316 | } 317 | 318 | .markdown-body dl dt { 319 | padding: 0; 320 | margin-top: 16px; 321 | font-size: 1em; 322 | font-style: italic; 323 | font-weight: 600; 324 | } 325 | 326 | .markdown-body dl dd { 327 | padding: 0 16px; 328 | margin-bottom: 16px; 329 | } 330 | 331 | .markdown-body table { 332 | display: block; 333 | width: 100%; 334 | overflow: auto; 335 | } 336 | 337 | .markdown-body table th { 338 | font-weight: 600; 339 | } 340 | 341 | .markdown-body table th, 342 | .markdown-body table td { 343 | padding: 6px 13px; 344 | border: 1px solid #dfe2e5; 345 | } 346 | 347 | .markdown-body table tr { 348 | background-color: #fff; 349 | border-top: 1px solid #c6cbd1; 350 | } 351 | 352 | .markdown-body table tr:nth-child(2n) { 353 | background-color: #f6f8fa; 354 | } 355 | 356 | .markdown-body img { 357 | max-width: 100%; 358 | box-sizing: content-box; 359 | background-color: #fff; 360 | } 361 | 362 | .markdown-body img[align=right] { 363 | padding-left: 20px; 364 | } 365 | 366 | .markdown-body img[align=left] { 367 | padding-right: 20px; 368 | } 369 | 370 | .markdown-body pre { 371 | padding: 16px; 372 | overflow: auto; 373 | font-size: 85%; 374 | line-height: 1.45; 375 | background-color: #f6f8fa; 376 | border-radius: 3px; 377 | word-wrap: normal; 378 | } 379 | .markdown-body :checked+.radio-label { 380 | position: relative; 381 | z-index: 1; 382 | border-color: #0366d6; 383 | } 384 | 385 | .markdown-body hr { 386 | border-bottom-color: #eee; 387 | } 388 | 389 | #log .v { 390 | color: #888888; 391 | } 392 | 393 | #log .d { 394 | color: #00DDDD; 395 | } 396 | 397 | #log .c { 398 | color: magenta; 399 | } 400 | 401 | #log .i { 402 | color: limegreen; 403 | } 404 | 405 | #log .w { 406 | color: yellow; 407 | } 408 | 409 | #log .e { 410 | color: red; 411 | font-weight: bold; 412 | } 413 | 414 | #log { 415 | background-color: #1c1c1c; 416 | } 417 | -------------------------------------------------------------------------------- /gasmeter.yaml: -------------------------------------------------------------------------------- 1 | ## ################################################################ 2 | ## ESP32 DEV - GAS & WASSER 2021 - SENSOREN 3 | ## ESP32 NodeMCU Module WLAN WiFi Development Board mit CP2102 4 | ## - GPIO19: Pulscounter Gaszähler 5 | ## ################################################################ 6 | esp32: 7 | board: esp32dev 8 | framework: 9 | type: arduino 10 | version: recommended 11 | 12 | substitutions: 13 | platform: ESP32 14 | board: esp32dev 15 | device_name_short: "gasmeter" # used by esp-home config 16 | friendly_name: "GM2021" 17 | device_description: "Gasmeter" 18 | update_interval: 60s 19 | impulsfactor: "0.100" 20 | appversion: "1.1.7" 21 | 22 | esphome: 23 | project: 24 | name: "gasmeter.esp32WUG" 25 | version: ${appversion} 26 | 27 | # ---------------------------------------------------------------- 28 | # Global variables 29 | # ---------------------------------------------------------------- 30 | globals: 31 | - id: z61count 32 | type: int 33 | restore_value: yes 34 | initial_value: "0" 35 | - id: z61counter 36 | type: float 37 | restore_value: yes 38 | initial_value: "0.0" 39 | - id: m3kw 40 | type: float 41 | restore_value: yes 42 | initial_value: "10.94" 43 | - id: gas_meter_displayinital 44 | type: float 45 | restore_value: yes 46 | initial_value: "29060.654" 47 | - id: gas_meter_displayvalue 48 | type: float 49 | restore_value: yes 50 | initial_value: "29246.433" 51 | - id: gas_meter_totalm3 52 | type: float 53 | restore_value: yes 54 | initial_value: "0.0" 55 | 56 | # --------------------------------------- 57 | # Base packages wifi, timeserver... 58 | # --------------------------------------- 59 | packages: 60 | base: !include common/base.yaml 61 | base_webserver: !include common/base_webserver.yaml 62 | base_global: !include common/base_global.yaml 63 | 64 | # ---------------------------------------------------------------- 65 | # Native API Component 66 | # ---------------------------------------------------------------- 67 | api: 68 | id: espapi 69 | port: 6053 70 | reboot_timeout: 5min 71 | services: 72 | - service: set_gasmeterdisplay 73 | variables: 74 | my_newdisplayvalue: float 75 | then: 76 | - logger.log: 77 | format: "Setting Gasmeter Display value: %.1f" 78 | args: [my_newdisplayvalue] 79 | - globals.set: 80 | id: gas_meter_displayvalue 81 | value: !lambda "return (my_newdisplayvalue);" 82 | - globals.set: 83 | id: z61counter 84 | value: !lambda "return (my_newdisplayvalue);" 85 | - globals.set: 86 | id: gas_meter_totalm3 87 | value: !lambda "return ((my_newdisplayvalue) - id(gas_meter_displayinital));" 88 | - globals.set: 89 | id: z61count 90 | value: !lambda "return ( ((my_newdisplayvalue) - id(gas_meter_displayinital))/${impulsfactor} );" 91 | - logger.log: 92 | format: "Gasmeter Display value: %.1f" 93 | args: [id(gas_meter_displayvalue)] 94 | 95 | # ---------------------------------------------------------------- 96 | # Switch to restart, reset all, reset bootcounter 97 | # ---------------------------------------------------------------- 98 | switch: 99 | - platform: template 100 | name: ${friendly_name} reset all 101 | turn_on_action: 102 | then: 103 | - lambda: |- 104 | id(boot_counter) = 0; 105 | id(z61counter) = 0.0; 106 | id(z61count) = 0; 107 | id(gas_meter_totalm3)= 0.0; 108 | id(gas_meter_displayvalue)= 0.0; 109 | id(daily_value)= 0.0; 110 | id(hour_value)= 0.0; 111 | id(bootcounter).update(); 112 | id(gas_meter_display).update(); 113 | id(gas_meter_total_m3).update(); 114 | id(gas_meter_total_kw).update(); 115 | id(gas_meter_total_kw_day).update(); 116 | - logger.log: ${device_name_short} all values reset! 117 | 118 | # ---------------------------------------------------------------- 119 | # GASCOUNTER ZI-61 REED CONTACT 120 | # GPIO19 <-- o-RC-o <--- GND 121 | # o-10k ----> +5V 122 | # +++++++++++++++++++++++++++++++ 123 | # Gasmeter: Krom Schröder BK-G,25 124 | # ++++++++++++++++++++++++++++++++ 125 | # Q_max: 4 m³/h 126 | # Q_min: 0.025 m³/h 127 | # V: 1.2 dm³ 128 | # p_max: 0.5 bar 129 | # 1 imp = 0.1 m³ 130 | # ---------------------------------------------------------------- 131 | binary_sensor: 132 | - platform: gpio 133 | pin: 134 | number: GPIO19 135 | mode: INPUT_PULLUP ## set ESP32 pin to input pull-up mode 136 | inverted: false 137 | name: ${friendly_name} Gaszähler Z-61 Impuls 138 | id: gassensor_state 139 | device_class: window 140 | filters: 141 | - delayed_off: 10ms 142 | ## This automation will be triggered when a button press ends, 143 | ## or in other words on the falling edge of the signal. 144 | on_release: 145 | then: 146 | - lambda: |- 147 | ESP_LOGI("main", " ------- Z-61 SET NEW VALUES !!!!!"); 148 | id(z61count) += 1; 149 | id(z61counter) += ${impulsfactor}; 150 | id(gas_meter_displayvalue) += ${impulsfactor}; 151 | id(gas_meter_totalm3) += ${impulsfactor}; 152 | id(daily_value) += ${impulsfactor}; 153 | id(hour_value) += ${impulsfactor}; 154 | id(gas_meter_display).update(); 155 | id(gas_meter_total_m3).update(); 156 | id(gas_meter_total_kw).update(); 157 | id(gas_meter_total_kw_day).update(); 158 | id(gas_meter_m3_today).publish_state(${impulsfactor}); 159 | 160 | # ---------------------------------------------------------------- 161 | # ALL SENSORS 162 | # ---------------------------------------------------------------- 163 | sensor: 164 | - platform: template 165 | name: ${friendly_name} Gasmeter Display 166 | id: gas_meter_display 167 | accuracy_decimals: 1 168 | unit_of_measurement: "m³" 169 | icon: "mdi:counter" 170 | device_class: gas 171 | lambda: |- 172 | return id(gas_meter_displayvalue); 173 | 174 | - platform: template 175 | name: ${friendly_name} Gasmeter current 176 | id: gas_meter_m3_today 177 | state_class: measurement 178 | device_class: gas 179 | unit_of_measurement: "m³" 180 | accuracy_decimals: 2 181 | 182 | - platform: template 183 | name: ${friendly_name} Gasmeter Impulse 184 | id: gas_meter_impulse_count 185 | state_class: measurement 186 | accuracy_decimals: 0 187 | lambda: |- 188 | return (id(z61count)); 189 | 190 | - platform: template 191 | name: ${friendly_name} Gas total 192 | id: gas_meter_total_m3 193 | accuracy_decimals: 1 194 | unit_of_measurement: "m³" 195 | device_class: gas 196 | state_class: total_increasing 197 | lambda: |- 198 | return id(gas_meter_totalm3); 199 | 200 | - platform: template 201 | name: ${friendly_name} Gas per today 202 | id: gas_meter_total_m3_day 203 | unit_of_measurement: "m³" 204 | state_class: total_increasing 205 | accuracy_decimals: 1 206 | icon: mdi:gauge 207 | lambda: |- 208 | return (id(daily_value)); 209 | 210 | - platform: template 211 | name: ${friendly_name} Gas per hour 212 | id: gas_meter_total_m3_hour 213 | unit_of_measurement: "m³" 214 | state_class: total_increasing 215 | accuracy_decimals: 1 216 | icon: mdi:gauge 217 | lambda: |- 218 | return (id(hour_value)); 219 | 220 | - platform: template 221 | name: ${friendly_name} Kilowattstunde Gas total 222 | id: gas_meter_total_kw 223 | accuracy_decimals: 2 224 | device_class: energy 225 | state_class: measurement 226 | unit_of_measurement: "kWh" 227 | lambda: |- 228 | return (id(gas_meter_totalm3) * id(m3kw)); 229 | 230 | - platform: template 231 | name: ${friendly_name} Kilowattstunde Gas today 232 | id: gas_meter_total_kw_day 233 | unit_of_measurement: "kWh" 234 | state_class: measurement 235 | device_class: energy 236 | accuracy_decimals: 2 237 | lambda: |- 238 | return (id(daily_value) * id(m3kw)); 239 | 240 | - platform: template 241 | name: ${friendly_name} Kilowattstunde Gas per hour 242 | id: gas_meter_total_kw_hour 243 | unit_of_measurement: "kWh" 244 | state_class: measurement 245 | device_class: energy 246 | accuracy_decimals: 2 247 | lambda: |- 248 | return (id(hour_value) * id(m3kw)); 249 | 250 | logger: 251 | level: NONE 252 | # baud_rate: 9600 253 | baud_rate: 0 254 | -------------------------------------------------------------------------------- /wasserundgas.yaml: -------------------------------------------------------------------------------- 1 | ## ################################################################ 2 | ## ESP32 DEV - GAS & WASSER 2021 - SENSOREN 3 | ## - GPIO12: Pulscounter Gaszähler 4 | ## - GPIO34: Druck Kaltwasser 5 | ## - GPIO17: Kaltwasser Temperatur 6 | ## ################################################################ 7 | substitutions: 8 | device_id: "wasserundgas" 9 | device_name: "wasserundgas" 10 | device_name_short: "wasserundgas" 11 | device_name_upper: "GWS" 12 | update_interval: 60s 13 | impulsfactor: "0.100" 14 | platform: ESP32 15 | board: esp32dev 16 | attribution: "Data provided by Peter Siebler" 17 | appversion: "1.0.4" 18 | topic_prefix: "tele/wasserundgas" 19 | topic_data: "tele/wasserundgas/data" 20 | device_description: "Gaszähler Kaltwassertemperatur, Kaltwasserdruck" 21 | 22 | esphome: 23 | name: $device_name 24 | comment: ${device_description} 25 | platform: ${platform} 26 | board: ${board} 27 | arduino_version: recommended 28 | project: 29 | name: "ips.home" 30 | version: ${appversion} 31 | on_boot: 32 | priority: -10 33 | then: 34 | - logger.log: "API is connected, Device ready!" 35 | 36 | # ---------------------------------------------------------------- 37 | # Global variables 38 | # ---------------------------------------------------------------- 39 | globals: 40 | - id: z61count 41 | type: int 42 | restore_value: yes 43 | initial_value: "0" 44 | - id: z61counter 45 | type: float 46 | restore_value: yes 47 | initial_value: "0.000" 48 | - id: m3kw 49 | type: float 50 | restore_value: yes 51 | initial_value: "10.94" 52 | - id: gas_meter_displayvalue 53 | type: float 54 | restore_value: yes 55 | initial_value: "29121.057" 56 | - id: gas_meter_totalm3 57 | type: float 58 | restore_value: yes 59 | initial_value: "0.000" 60 | - id: daily_value 61 | type: float 62 | restore_value: yes 63 | initial_value: "0.000" 64 | 65 | # ---------------------------------------------------------------- 66 | # MQTT Client Component 67 | # ---------------------------------------------------------------- 68 | # see: https://esphome.io/components/mqtt.html?highlight=mqtt 69 | # inlude mqtt broker and wifi settings w/o api 70 | # sets wifi, ap, domain, default logger, ota password, webserver 71 | # time sntp, mqtt brocker. 72 | <<: !include common/mqttonly.yaml 73 | 74 | # ---------------------------------------------------------------- 75 | # Logger settings 76 | # ---------------------------------------------------------------- 77 | logger: 78 | level: INFO 79 | logs: 80 | mqtt.component: ERROR 81 | mqtt.client: ERROR 82 | 83 | # ---------------------------------------------------------------- 84 | # GPIO02: used for temperatur sensors data wired 85 | # ---------------------------------------------------------------- 86 | dallas: 87 | pin: GPIO17 88 | update_interval: ${update_interval} 89 | 90 | switch: 91 | # Switch to restart 92 | - platform: restart 93 | name: ${device_name_upper} restart 94 | 95 | # ---------------------------------------------------------------- 96 | # GASCOUNTER ZI-61 REED CONTACT 97 | # ---------------------------------------------------------------- 98 | binary_sensor: 99 | - platform: gpio 100 | pin: 101 | number: GPIO12 102 | mode: INPUT_PULLUP 103 | inverted: false 104 | name: ${device_name_upper} Gaszähler Z-61 Impuls 105 | id: gassensor_state 106 | device_class: window 107 | filters: 108 | - delayed_off: 10ms 109 | on_release: 110 | then: 111 | - lambda: |- 112 | id(z61counter) += ${impulsfactor}; 113 | id(z61count) += 1; 114 | id(gas_meter_totalm3) += ${impulsfactor}; 115 | id(gas_meter_displayvalue) += ${impulsfactor}; 116 | id(daily_value) += ${impulsfactor}; 117 | id(gas_meter_display).update(); 118 | id(gas_meter_total_m3).update(); 119 | id(gas_meter_total_kw).update(); 120 | id(gas_meter_total_kw_day).update(); 121 | 122 | # ---------------------------------------------------------------- 123 | # ALL SENSORS 124 | # ---------------------------------------------------------------- 125 | sensor: 126 | - platform: template 127 | name: ${device_name_upper} Gaszähler Anzeige 128 | id: gas_meter_display 129 | accuracy_decimals: 3 130 | unit_of_measurement: "m³" 131 | icon: "mdi:counter" 132 | state_topic: ${topic_prefix}/gas_meter_displayvalue 133 | lambda: |- 134 | return id(gas_meter_displayvalue); 135 | 136 | - platform: template 137 | name: ${device_name_upper} Gasverbrauch 138 | id: gas_meter_total_m3 139 | accuracy_decimals: 3 140 | unit_of_measurement: "m³" 141 | state_topic: ${topic_prefix}/gas_total_m3 142 | lambda: |- 143 | return id(gas_meter_totalm3); 144 | 145 | - platform: template 146 | name: ${device_name_upper} Gasverbrauch kW 147 | id: gas_meter_total_kw 148 | accuracy_decimals: 3 149 | unit_of_measurement: "kW" 150 | state_topic: ${topic_prefix}/gas_total_kw 151 | lambda: |- 152 | return (id(gas_meter_totalm3) * id(m3kw)); 153 | 154 | - platform: template 155 | name: ${device_name_upper} Gasverbrauch heute 156 | id: gas_meter_total_kw_day 157 | unit_of_measurement: "kW" 158 | lambda: |- 159 | return (id(daily_value) * id(m3kw)); 160 | 161 | # ----------------------------------------------------- 162 | # DFRobot SEN0257 water pressure sensor 1 GPIO 34 163 | # ----------------------------------------------------- 164 | - platform: adc 165 | name: ${device_name_upper} Kaltwasser Wasserdruck 166 | pin: GPIO34 167 | id: coldwater_pressure 168 | update_interval: 10s 169 | unit_of_measurement: "bar" 170 | accuracy_decimals: 2 171 | attenuation: 11db 172 | state_topic: ${topic_prefix}/coldwater_pressure 173 | filters: 174 | - lambda: |- 175 | if(x-0.41<0) return 0.00; 176 | return ((x) * 2.00) - 0.82; 177 | 178 | # ------------------------------------------------------------------------------ 179 | # PIN GIPO17: DS18B20 Digital temperature sensor 1 180 | # For this, connect a resistor of about 4.7KΩ (values around that like 1KΩ will, 181 | # if you don’t have massively long wires, work fine in most cases) 182 | # between 3.3V and the data pin. 183 | # Unique ID: 'dallas-7900000C8579C728' 184 | # ------------------------------------------------------------------------------ 185 | - platform: dallas 186 | # index: 0 187 | address: 0x7900000C8579C728 188 | accuracy_decimals: 2 189 | unit_of_measurement: "°C" 190 | name: ${device_name_upper} Kaltwasser Temperatur 191 | id: coldwater_temperature 192 | icon: mdi:thermometer-lines 193 | state_topic: ${topic_prefix}/coldwater_temperature 194 | 195 | - platform: wifi_signal 196 | id: wifisignal 197 | name: ${device_name_upper} WiFi Signal 198 | update_interval: 60s 199 | 200 | # ----------------------------------------------- 201 | # additional sensors 202 | # ----------------------------------------------- 203 | - platform: uptime 204 | name: ${device_name_upper} Uptime Sensor 205 | id: uptime_sensor 206 | update_interval: ${update_interval} 207 | on_raw_value: 208 | then: 209 | - text_sensor.template.publish: 210 | id: uptime_human 211 | state: !lambda |- 212 | int seconds = round(id(uptime_sensor).raw_state); 213 | int days = seconds / (24 * 3600); 214 | seconds = seconds % (24 * 3600); 215 | int hours = seconds / 3600; 216 | seconds = seconds % 3600; 217 | int minutes = seconds / 60; 218 | seconds = seconds % 60; 219 | return ( 220 | (days ? String(days) + "d " : "") + 221 | (hours ? String(hours) + "h " : "") + 222 | (minutes ? String(minutes) + "m " : "") + 223 | (String(seconds) + "s") 224 | ).c_str(); 225 | on_value: 226 | - mqtt.publish_json: 227 | topic: "tele/wasserundgas/data" 228 | payload: !lambda |- 229 | root["name_pretty"] = "${device_name_upper}"; 230 | root["gas_meter_sensor"] = id(gassensor_state).state; 231 | root["gas_display"] = id(gas_meter_display).state; 232 | root["gas_meter_total_m3"] = id(gas_meter_total_m3).state; 233 | root["gas_meter_total_kw"] = id(gas_meter_total_kw).state; 234 | root["z61counter"] = id(z61counter); 235 | root["z61count"] = id(z61count); 236 | root["coldwater_pressure"] = isnan(id(coldwater_pressure).state)?0:id(coldwater_pressure).state; 237 | root["coldwater_temperature"] = isnan(id(coldwater_temperature).state)?0:id(coldwater_temperature).state; 238 | root["wifi_signal"] = id(wifisignal).state; 239 | root["wif_iip"] = id(wifiip).state; 240 | root["wifi_ssid"] = id(wifissid).state; 241 | root["wifi_bssid"] = id(wifibssid).state; 242 | root["version"] = id(appver).state; 243 | root["timestamp"] = id(systime).state; 244 | root["uptime"] = id(uptime_sensor).state; 245 | root["uptime_human"] = id(uptime_human).state; 246 | root["appversion"] = "${appversion}"; 247 | root["attribution"] = "${attribution}"; 248 | 249 | ## ----------------------------------------------------------- 250 | ## additional sensor data 251 | ## ----------------------------------------------------------- 252 | text_sensor: 253 | - platform: version 254 | name: ${device_name_upper} Version 255 | id: appver 256 | 257 | - platform: template 258 | name: ${device_name_upper} Online seit 259 | id: uptime_human 260 | icon: mdi:clock-start 261 | 262 | - platform: wifi_info 263 | ip_address: 264 | name: ${device_name_upper} IP 265 | id: wifiip 266 | icon: mdi:ip-network 267 | 268 | ssid: 269 | name: ${device_name_upper} SSID 270 | id: wifissid 271 | 272 | bssid: 273 | id: wifibssid 274 | name: ${device_name_upper} BSSID 275 | 276 | - platform: template 277 | name: ${device_name_upper} Timestamp 278 | id: systime 279 | lambda: char str[20]; 280 | time_t currTime = id(sntp_time).now().timestamp; 281 | strftime(str, sizeof(str), "%Y-%m-%dT%H:%M:%S", localtime(&currTime)); 282 | return (std::string) str; 283 | --------------------------------------------------------------------------------