Skip to content

Commit

Permalink
smartmeter: update webif
Browse files Browse the repository at this point in the history
  • Loading branch information
Morg42 committed Dec 22, 2024
1 parent ad2d812 commit 4b114ee
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 99 deletions.
10 changes: 7 additions & 3 deletions smartmeter/webif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import time
import os
import json
import pprint

from lib.item import Items
from lib.model.smartplugin import SmartPluginWebIf
Expand Down Expand Up @@ -74,7 +75,8 @@ def index(self, reload=None):
return tmpl.render(p=self.plugin,
webif_pagelength=pagelength,
items=self.plugin.get_item_list(),
item_count=len(self.plugin.get_item_list()))
item_count=len(self.plugin.get_item_list()),
)

@cherrypy.expose
def get_data_html(self, dataSet=None):
Expand Down Expand Up @@ -120,7 +122,7 @@ def get_data_html(self, dataSet=None):
@cherrypy.expose
def submit(self, cmd=None):

self.logger.warning(f"submit: {cmd=}")
self.logger.debug(f"submit: {cmd=}")
result = None

if cmd == "detect":
Expand All @@ -129,7 +131,8 @@ def submit(self, cmd=None):
elif cmd == 'query':
result = self.plugin.query(assign_values=False)

self.logger.warning(f"submit: {result=}")
elif cmd == 'create_items':
result = self.plugin.create_items()

if result is not None:
# JSON zurücksenden
Expand All @@ -140,3 +143,4 @@ def submit(self, cmd=None):
@cherrypy.expose
def read_data(self):
self.plugin.query(assign_values=False)

270 changes: 174 additions & 96 deletions smartmeter/webif/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,46 @@
Additional script tag for plugin specific javascript code go into this block
-->
{% block pluginscripts %}
<script>
function updateButton(buttonElement, success, hide = false) {

const originalHTML = buttonElement.html();

if (success == "btn-success")
buttonElement
.prop("disabled", true)
.addClass(success);
else
buttonElement
.prop("disabled", true)
.addClass(success);

// After 2 seconds, revert the button to its original state
setTimeout(function() {
buttonElement
.prop("disabled", false)
.html(originalHTML)
.removeClass(success)

if (hide)
buttonElement.hide();
}, 2000);
}
</script>

<script>
function jsonToKeyValueLines(jsonData) {
let output = "";
for (const key in jsonData) {
if (jsonData.hasOwnProperty(key)) {
output += `${key}: ${jsonData[key]}<br>`;
}
}
console.log("jsonToKeyValueLines: " + output)
return output;
}
</script>

<script>
function handleUpdatedData(response, dataSet=null) {
if (dataSet === 'devices_info' || dataSet === null) {
Expand All @@ -80,16 +120,17 @@
shngInsertText(item+'_value', objResponse['items'][item]['value'], 'maintable', 5);
shngInsertText(item+'_last_update', objResponse['items'][item]['last_update'], 'maintable', 5);
shngInsertText(item+'_last_change', objResponse['items'][item]['last_change'], 'maintable', 5);
}

for (obis in objResponse['obis_results']) {
var obis_data = objResponse['obis_results'][obis][0];
var obis_data_formatted = jsonToKeyValueLines(obis_data);
console.log("DOM: " + obis+'_value');
console.log("VAL: " + JSON.stringify(obis_data));
shngInsertText(obis+'_value', JSON.stringify(obis_data), 'obis_data_table', 5);
}
console.log("VAL: " + obis_data_formatted);
shngInsertText(obis+'_value', obis_data_formatted, 'obis_data_table', 5);
}
// Redraw datatable after cell updates
// $('#maintable').DataTable().draw(false);
$('#maintable').DataTable().draw(false);
$('#obis_data_table').DataTable().draw(false);
}
}
Expand All @@ -100,78 +141,107 @@
-->
<script>
$(document).ready( function () {
// Handler für einfachen Button - das "click"-Element wird abgefangen
$("#detect").click(function(e) {

// keine HTML-Aktion ausführen (z.B. Formular senden)
e.preventDefault();

console.log('Sending smartmeter command: detect');

// festen Wert per AJAX senden
$.post('submit', {cmd: "detect"}, function(data) {

console.log("Return from plugin: cmd=detect, data=" + data);
for (var row in data) {
console.log("row=" + row + ", data=" + data.row);
}

// Ergebnis in Feld #fromip schreiben. Der dritte Parameter muss mit der Tabellen-ID identisch sein.
shngInsertText('protocol', data.protocol, 'headtable')
});
return false ;
});
$("#query").click(function(e) {

// keine HTML-Aktion ausführen (z.B. Formular senden)
e.preventDefault();

console.log('Sending smartmeter command: query');

// festen Wert per AJAX senden
$.post('submit', {cmd: "query"}, function(data) {

console.log("Return from plugin: cmd=query, data=" + data);

for (var obis in data) {
var obis_data = data[obis][0];
console.log("obis=" + obis, "data=" + JSON.stringify(obis_data));

if (!document.getElementById(obis+'_value')) {
if ( $.fn.dataTable.isDataTable('#obis_data_table') ) {

// Define target table
var table_to_update = $('#obis_data_table').DataTable();

// Create a new row object
var newRow = ['', obis, JSON.stringify(obis_data)];

// Add the row to the table and get the node
var rowNode = table_to_update.row.add(newRow).draw(false).node();

// Assign IDs to the cells
$(rowNode).children('td').each(function(index, cell) {
if (index === 1) {
$(cell).attr('id', obis);
} else {
$(cell).attr('id', obis + '_value');
}
});

shngInsertText(obis+'_value', JSON.stringify(obis_data), 'obis_data_table', 10);

}
}
else
{
console.log("Update existing table row; id="+obis+'_value');
shngInsertText(obis+'_value', JSON.stringify(obis_data), 'obis_data_table', 10);
}
}
$('#obis_data_table').DataTable().draw(false);
});
return false ;
});
// Handler für Formular - das "submit"-Element (Senden) wird abgefangen
$("#button_pressed").submit(function(e) {

// keine HTML-Aktion ausführen (z.B. Formular senden)
e.preventDefault();
let value = $("#button").val();
const id = $("#button_id").val();
const escapedId = $.escapeSelector(id);
const buttonElement = $("#" + escapedId);

console.log('Sending smartmeter plugin cmd: ' + id);

// die Kennung des gedrückten Buttons per AJAX senden
$.post('submit', {cmd: id}, function(data) {
console.log("Return value from plugin: cmd=" + id + ", data=" + JSON.stringify(data));

if (id === 'detect') {
// Update button based on discovery success
if (data.discovery_successful) {
updateButton(buttonElement, 'btn-success', "true");
alert('Ermittlung des Smartmeter-Protokoll erfolgreich!');
} else {
updateButton(buttonElement, 'btn-danger');
alert('Ermittlung des Smartmeter-Protokoll fehlgeschlagen!');
}

// Update datatables
shngInsertText('protocol', data.protocol, 'headtable');

}

if (id == 'query') {

// Update button
if (data) {
updateButton(buttonElement, "btn-success");
alert('Auslesen des Smartmeter erfolgreich!');

} else {
updateButton(buttonElement, "btn-danger");
alert('Auslesen des Smartmeter fehlgeschlagen!');
}

// Update datatables
for (var obis in data) {
var obis_data = data[obis][0];
var obis_data_formatted = jsonToKeyValueLines(obis_data);

console.log("obis=" + obis, "data=" + obis_data_formatted);
if (!document.getElementById(obis+'_value')) {
if ( $.fn.dataTable.isDataTable('#obis_data_table') ) {
// Define target table
var table_to_update = $('#obis_data_table').DataTable();
// Create a new row object
var newRow = ['', obis, obis_data_formatted];
// Add the row to the table and get the node
var rowNode = table_to_update.row.add(newRow).draw(false).node();
// Assign IDs to the cells
$(rowNode).children('td').each(function(index, cell) {
if (index === 1) {
$(cell).attr('id', obis);
} else {
$(cell).attr('id', obis + '_value');
}
});
shngInsertText(obis+'_value', obis_data_formatted, 'obis_data_table', 10);
}
}
else
{
console.log("Update existing table row; id="+obis+'_value');
shngInsertText(obis+'_value', obis_data_formatted, 'obis_data_table', 10);
}
}
$('#obis_data_table').DataTable().draw(false);

}

if (id == 'create_items') {

// Update button
if (data === true) {
updateButton(buttonElement, "btn-success", "true");
alert('Item Erstellung erfolgreich!');
} else {
updateButton(buttonElement, "btn-danger");
alert('Item Erstellung fehlgeschlagen!');
}

// Update datatables
shngInsertText('protocol', data.protocol, 'headtable');

}

}).fail(function(jqXHR, textStatus, errorThrown) {
// Error callback
console.error("AJAX request failed:", textStatus, errorThrown);
updateButton(buttonElement, "btn-danger");
});
return false ;
});

// Handler responsive Tabelle und deren Überschriften
/*
Expand Down Expand Up @@ -262,7 +332,7 @@
},
{
title: '{{ _('Wert') }}',
targets: [2], "className": "type"
targets: [2], "className": ""
},
].concat($.fn.dataTable.defaults.columnDefs),
});
Expand Down Expand Up @@ -309,12 +379,12 @@
<td></td>
</tr>
<tr>
<td class="py-1"><strong>Verbunden</strong></td>
<td class="py-1">{% if p.use_asyncio %}{% if p.connected %}{{ _('Ja') }}{% else %}{{ _('Nein') }}{% endif %}{% else %}{{ _('-') }}{% endif %}</td>
<td class="py-1"><strong>Abfrageintervall</strong></td>
<td class="py-1">{% if p.cycle %}{{ p.cycle }}s{% endif %}{% if p.crontab %}{{ p.crontab }}{% endif %}</td>
<td class="py-1"><strong>Async-Verwendung</strong></td>
<td class="py-1">{% if p.use_asyncio %}{{ _('Ja') }}{% else %}{{ _('Nein') }}{% endif %}</td>
<td class="py-1">{% if p.use_asyncio %}<strong>Verbunden</strong>{% else %}{{ '' }}{% endif %}</td>
<td class="py-1">{% if p.use_asyncio %}{% if p.connected %}{{ _('Ja') }}{% else %}{{ _('Nein') }}{% endif %}{% endif %}</td>
<td class="py-1"><strong>Abfrage</strong></td>
<td class="py-1">{% if p.cycle %} {{ p.cycle }}s {% elif p.crontab %} {{ p.crontab }} {% elif p.use_asyncio %} {{ _('kontinuierlich') }} {% endif %}</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Expand All @@ -324,16 +394,21 @@
{% block buttons %}
<div>
{% if not p.protocol %}
<button id="detect" class="btn btn-shng btn-sm" type="button">{{_('Discovery starten')}}</button>
<button id="detect" type="button" class="btn btn-shng btn-sm" title="Erkenne Smartmeter Protokoll" onclick="$('#button_id').val(this.id);$('#button').val(this.value);$('#button_pressed').submit();"><i class="fas"></i>{{_('Discovery starten')}}</button>
{% endif %}
<button id="query" class="btn btn-shng btn-sm" type="button">{{_('Abfrage starten')}}</button>
<button id="query" type="button" class="btn btn-shng btn-sm" title="Smartmeter auslesen" onclick="$('#button_id').val(this.id);$('#button').val(this.value);$('#button_pressed').submit();"><i class="fas"></i>{{_('Smartmeter auslesen')}}</button>
<button id="create_items" type="button" class="btn btn-shng btn-sm" title="Items erstellen" onclick="$('#button_id').val(this.id);$('#button').val(this.value);$('#button_pressed').submit();"><i class="fas"></i>{{_('Items erstellen')}}</button>
</div>
<form id="button_pressed" action="" method="post">
<input type="hidden" id="button" name="button" value="" />
<input type="hidden" id="button_id" name="button_id" value="">
</form>
{% endblock %}


{% set tabcount = 3 %}

{% set start_tab = 2 %}
{% set start_tab = 1 %}
{% if item_count==0 %}
{% set start_tab = 2 %}
{% endif %}
Expand All @@ -348,10 +423,10 @@
<td></td>
<td class="py-1" id="{{ item._path }}">{{ item.property.path }}</td>
<td class="py-1">{{ item._type }}</td>
<td class="py-1">{{ item.conf['obis_code'] }}</td>
<td class="py-1">{{ item.conf['obis_index'] }}</td>
<td class="py-1">{{ item.conf['obis_property'] }}</td>
<td class="py-1">{{ item.conf['obis_vtype'] }}</td>
<td class="py-1">{{ p.get_iattr_value(item.conf, 'obis_code', '') }}</td>
<td class="py-1">{{ p.get_iattr_value(item.conf, 'obis_index', '0') }}</td>
<td class="py-1">{{ p.get_iattr_value(item.conf, 'obis_property', 'value') }}</td>
<td class="py-1">{{ p.get_iattr_value(item.conf, 'obis_vtype', '-') }}</td>
<td class="py-1" id="{{ item._path }}_value">{{ item.property.value }}</td>
<td class="py-1" id="{{ item._path }}_last_update" style="text-align: center">&nbsp;</td>
<td class="py-1" id="{{ item._path }}_last_change" style="text-align: center">&nbsp;</td>
Expand All @@ -368,19 +443,22 @@
<table id="obis_data_table" class="dataTableAdditional m-2">
<tbody>
{% for obis in p.obis_results %}
<tr>
<td></td>
<td class="py-1" id="{{ obis }}">{{ obis }}</td>
<td class="py-1" id="{{ obis }}_value">''</td>
</tr>
<tr>
<td></td>
<td class="py-1" id="{{ obis }}">{{ obis }}</td>
<td class="py-1" id="{{ obis }}_value">''</tr>
{% endfor %}
</tbody>
</table>
{% endblock bodytab2 %}



{% set tab3title = "<strong>" "Zählerstatus</strong>" %}
{% if p.protocol in ['SML', 'sml'] %}
{% set tab3title = "<strong>" "Zählerstatus</strong>" %}
{% else %}
{% set tab3title = "hidden" %}
{% endif %}
{% block bodytab3 %}
<table id="status_table" class="dataTableAdditional m-2">
<tbody>
Expand Down

0 comments on commit 4b114ee

Please sign in to comment.