Hey Leute,
mir fehlen leider die Programmierkentnnise um das HTML Widget selber zu machen also habe ich mir mit Claude.ai etwas Hilfe geholt.
Ich bin auch fast am Ziel meines Vorhabens allerdings bekomme ich einen Fehler seit Stunden nicht heraus.
Ich habe mir ein Widget gemacht wo ich Jalousien direkt hoch und runter fahren kann. Und links davon der aktuelle Status von der Jalousie angezeigt werden soll

Hier ist bereits der erste Fehler weil da 0% angezeigt wird statt der echte Wert.
Wenn ich auf das Widget klicke wird ein PopUp geöffnet mit mehr Funktionen, auch hier werden die aktuellen Werte nicht angezeigt.

Der Regler funktioniert und die Prozente werden beim bedienen angezeigt,
allerdings nur solange das PopUp offen ist. sobal ich das schliese und neu öffne steht oben wieder 0
P.S im Editor wird die Jalousien Position agezeigt

Ich gehe aktuell also davon aus, dass auch die Werte im PopUp im Editor angezeigt werden und das das Problem nur in der VIS Ansicht ist.
Das ist der Code dazu
<style>
.jalousie-widget-container {
width: 100%;
height: 100%;
box-sizing: border-box;
border-radius: 20px;
padding: 0;
background: #f5f5f5;
font-family: sans-serif;
position: relative;
margin: 0 auto;
border: 1px solid #e0e0e0;
display: flex;
flex-direction: column;
}
.jalousie-widget-header {
display: flex;
align-items: center;
padding: calc(min(10px, 3%));
border-bottom: 1px dotted #ccc;
flex: 0 0 auto;
}
.jalousie-widget-icon {
width: calc(min(24px, 15%));
height: calc(min(24px, 15%));
margin-right: calc(min(10px, 3%));
min-width: 16px;
min-height: 16px;
}
.jalousie-widget-title {
font-size: calc(min(14px, 4vw));
margin: 0;
padding: calc(min(8px, 3%)) 0;
text-align: left;
border-bottom: 1px dotted #ccc;
padding-left: calc(min(10px, 3%));
flex: 0 0 auto;
}
.jalousie-widget-status {
display: flex;
align-items: center;
padding: calc(min(10px, 3%)) calc(min(12px, 4%));
justify-content: space-between;
flex: 1 0 auto;
}
.jalousie-status-text {
font-size: calc(min(16px, 4.5vw));
margin: 0;
font-weight: 500;
}
.jalousie-widget-buttons {
display: flex;
}
.jalousie-widget-button {
width: calc(min(44px, 35%));
height: calc(min(44px, 35%));
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
background: white;
border-radius: 50%;
margin-left: 8px;
cursor: pointer;
font-size: calc(min(26px, 8vw));
padding: 0;
min-width: 40px;
min-height: 40px;
font-weight: bold;
color: #333;
}
.jalousie-popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: none;
z-index: 9998;
touch-action: none;
}
.jalousie-popup {
display: none;
position: fixed;
top: 5%;
left: 5%;
width: 90%;
height: 90%;
max-height: 90vh;
background: white;
border-radius: 8px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
z-index: 9999;
font-family: sans-serif;
overflow: hidden;
touch-action: none;
}
.jalousie-popup.active {
display: flex;
flex-direction: column;
}
.jalousie-popup-header {
padding: 15px;
border-bottom: 1px solid #eee;
font-size: 18px;
font-weight: 500;
display: flex;
justify-content: space-between;
align-items: center;
}
.jalousie-popup-status {
padding: 15px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
background: #f9f9f9;
}
.jalousie-popup-status-item {
display: flex;
align-items: center;
}
.jalousie-popup-status-label {
font-size: 14px;
color: #666;
margin-right: 10px;
}
.jalousie-popup-status-value {
font-size: 16px;
font-weight: bold;
}
.jalousie-popup-content {
flex: 1;
display: flex;
padding: 20px;
justify-content: center;
overflow: hidden;
touch-action: none;
}
.jalousie-sliders-container {
display: flex;
width: 100%;
max-width: 600px;
justify-content: space-around;
align-items: flex-start;
}
.jalousie-slider-column {
display: flex;
flex-direction: column;
align-items: center;
width: 45%;
}
.jalousie-slider-wrapper {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
max-height: 500px;
}
.jalousie-slider-icon {
margin-bottom: 10px;
width: 24px;
height: 24px;
}
.jalousie-slider-vertical {
-webkit-appearance: slider-vertical;
appearance: slider-vertical;
height: 80%;
min-height: 200px;
width: 50px;
margin: 20px 0;
transform: rotate(180deg);
background: #e0e0e0;
border-radius: 25px;
outline: none;
cursor: pointer;
}
.jalousie-slider-vertical::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 60px;
height: 60px;
background: #007bff;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 0 5px rgba(0,0,0,0.2);
}
.jalousie-slider-vertical::-moz-range-thumb {
width: 60px;
height: 60px;
background: #007bff;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 0 5px rgba(0,0,0,0.2);
border: none;
}
.jalousie-slider-label {
font-size: 16px;
margin-top: 10px;
text-align: center;
}
.jalousie-slider-buttons {
display: flex;
gap: 10px;
margin-top: 15px;
}
.jalousie-slider-button {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
background: white;
border-radius: 50%;
cursor: pointer;
font-size: 24px;
padding: 0;
font-weight: bold;
touch-action: manipulation;
color: #333;
}
.jalousie-slider-button:hover {
background: #f5f5f5;
}
.jalousie-slider-button:active {
background: #e0e0e0;
}
.jalousie-popup-footer {
padding: 15px;
border-top: 1px solid #eee;
display: flex;
justify-content: space-between;
}
.jalousie-popup-button {
padding: 10px 20px;
background: #f5f5f5;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
color: #333;
}
.jalousie-popup-button:hover {
background: #eee;
}
.jalousie-value-display {
font-size: 20px;
font-weight: bold;
margin-top: 10px;
margin-bottom: 20px;
}
</style>
<div class="jalousie-widget-container" id="dg-buero-jalousie-widget">
<div class="jalousie-widget-header">
<svg id="dg-buero-jalousie-icon" class="jalousie-widget-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="cursor: pointer;">
<rect x="4" y="4" width="16" height="16" rx="2" />
<line x1="4" y1="12" x2="20" y2="12" />
<line x1="7" y1="8" x2="17" y2="8" />
<line x1="7" y1="16" x2="17" y2="16" />
</svg>
</div>
<div class="jalousie-widget-title">
DG Büro
</div>
<div class="jalousie-widget-status">
<div class="jalousie-status-text">
<span id="dg-buero-jalousie-status">0</span>%
</div>
<div class="jalousie-widget-buttons">
<button id="dg-buero-btn-up" class="jalousie-widget-button">↑</button>
<button id="dg-buero-btn-down" class="jalousie-widget-button">↓</button>
</div>
</div>
</div>
<div id="dg-buero-jalousie-popup-overlay" class="jalousie-popup-overlay"></div>
<div id="dg-buero-jalousie-popup" class="jalousie-popup">
<div class="jalousie-popup-header">
DG Büro
<button id="dg-buero-close-popup" style="background: none; border: none; font-size: 20px; cursor: pointer; color: #333;">×</button>
</div>
<div class="jalousie-popup-status">
<div class="jalousie-popup-status-item">
<span class="jalousie-popup-status-label">Jalousie:</span>
<span class="jalousie-popup-status-value" id="dg-buero-popup-status-jalousie">0%</span>
</div>
<div class="jalousie-popup-status-item">
<span class="jalousie-popup-status-label">Lamellen:</span>
<span class="jalousie-popup-status-value" id="dg-buero-popup-status-lamellen">0%</span>
</div>
</div>
<div class="jalousie-popup-content">
<div class="jalousie-sliders-container">
<div class="jalousie-slider-column">
<div class="jalousie-slider-wrapper">
<svg class="jalousie-slider-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="6" y="4" width="12" height="16" rx="1" />
<line x1="6" y1="8" x2="18" y2="8" />
<line x1="6" y1="12" x2="18" y2="12" />
<line x1="6" y1="16" x2="18" y2="16" />
</svg>
<div class="jalousie-value-display"><span id="dg-buero-popup-jalousie-value">0</span>%</div>
<input type="range" min="0" max="100" value="0" id="dg-buero-slider-jalousie" class="jalousie-slider-vertical" orient="vertical" />
<div class="jalousie-slider-label">Position Jalousie</div>
<div class="jalousie-slider-buttons">
<button id="dg-buero-btn-jalousie-up" class="jalousie-slider-button">↑</button>
<button id="dg-buero-btn-jalousie-down" class="jalousie-slider-button">↓</button>
</div>
</div>
</div>
<div class="jalousie-slider-column">
<div class="jalousie-slider-wrapper">
<svg class="jalousie-slider-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 3 L4 10 L20 10 Z" />
<path d="M12 10 L4 17 L20 17 Z" />
</svg>
<div class="jalousie-value-display"><span id="dg-buero-popup-lamellen-value">0</span>%</div>
<input type="range" min="0" max="100" value="0" id="dg-buero-slider-lamellen" class="jalousie-slider-vertical" orient="vertical" />
<div class="jalousie-slider-label">Position Lamellen</div>
<div class="jalousie-slider-buttons">
<button id="dg-buero-btn-lamellen-up" class="jalousie-slider-button">↑</button>
<button id="dg-buero-btn-lamellen-down" class="jalousie-slider-button">↓</button>
</div>
</div>
</div>
</div>
</div>
<div class="jalousie-popup-footer">
<button id="dg-buero-btn-stop" class="jalousie-popup-button">STOP</button>
<div>
<button id="dg-buero-btn-preset-1" class="jalousie-popup-button">50%</button>
<button id="dg-buero-btn-preset-2" class="jalousie-popup-button">100%</button>
</div>
</div>
</div>
<script>
// Datenpunkte definieren - Diese müssen an dein ioBroker-System angepasst sein
const statusDP = 'openknx.0.Status.Jalousinen_Lamellen.Position_Jalousine_DG_Büro_status'; // For main widget display
const statusJalousieDP = 'openknx.0.Status.Jalousinen_Lamellen.Position_Jalousine_DG_Büro_status'; // Jalousie status in popup
const statusLamellenDP = 'openknx.0.Status.Jalousinen_Lamellen.Position_Lamellen_DG_Büro_status'; // Lamella status in popup
const lamellenDP = 'openknx.0.Schalten.Jalousinen.DG_Büro_Balkon_Lamellen';
const jalousienDP = 'openknx.0.Schalten.Jalousinen.DG_Büro_Balkon_Jalousien';
const absoluteJalousieDP = 'openknx.0.Schalten.Jalousinen.DG_Büro_Absolute_Position_Jalousine';
const absoluteLamellenDP = 'openknx.0.Schalten.Jalousinen.DG_Büro_Absolute_Position_Lamellen';
let holdTimeout;
let statusValue = 0;
let jalousieValue = 0; // Status value for jalousie
let lamellenValue = 0; // Status value for lamella
// DOM-Elemente
const btnUp = document.getElementById('dg-buero-btn-up');
const btnDown = document.getElementById('dg-buero-btn-down');
const jalousieIcon = document.getElementById('dg-buero-jalousie-icon');
const closePopup = document.getElementById('dg-buero-close-popup');
const jalousiePopup = document.getElementById('dg-buero-jalousie-popup');
const popupOverlay = document.getElementById('dg-buero-jalousie-popup-overlay');
const statusElement = document.getElementById('dg-buero-jalousie-status');
const sliderJalousie = document.getElementById('dg-buero-slider-jalousie');
const sliderLamellen = document.getElementById('dg-buero-slider-lamellen');
// DOM-Elemente für die Popup-Werte
const popupJalousieValue = document.getElementById('dg-buero-popup-jalousie-value');
const popupLamellenValue = document.getElementById('dg-buero-popup-lamellen-value');
const popupStatusJalousie = document.getElementById('dg-buero-popup-status-jalousie');
const popupStatusLamellen = document.getElementById('dg-buero-popup-status-lamellen');
const btnStop = document.getElementById('dg-buero-btn-stop');
const btnPreset1 = document.getElementById('dg-buero-btn-preset-1');
const btnPreset2 = document.getElementById('dg-buero-btn-preset-2');
// Additional popup buttons
const btnJalousieUp = document.getElementById('dg-buero-btn-jalousie-up');
const btnJalousieDown = document.getElementById('dg-buero-btn-jalousie-down');
const btnLamellenUp = document.getElementById('dg-buero-btn-lamellen-up');
const btnLamellenDown = document.getElementById('dg-buero-btn-lamellen-down');
// Funktion für das Senden von Werten an Datenpunkte
function sendToDP(dp, value) {
if (typeof vis !== 'undefined') {
vis.setValue(dp, value);
} else {
console.log('Sending to ' + dp + ': ' + value);
}
}
// Funktion für das Halten von Tasten
function setupHoldButton(button, shortDP, longDP, value) {
button.addEventListener('mousedown', function() {
holdTimeout = setTimeout(function() {
sendToDP(longDP, value);
holdTimeout = null;
}, 400);
});
button.addEventListener('mouseup', function() {
if (holdTimeout) {
clearTimeout(holdTimeout);
sendToDP(shortDP, value);
}
});
button.addEventListener('mouseleave', function() {
if (holdTimeout) {
clearTimeout(holdTimeout);
}
});
// Touch-Unterstützung für mobile Geräte
button.addEventListener('touchstart', function(e) {
e.preventDefault();
holdTimeout = setTimeout(function() {
sendToDP(longDP, value);
holdTimeout = null;
}, 400);
});
button.addEventListener('touchend', function(e) {
e.preventDefault();
if (holdTimeout) {
clearTimeout(holdTimeout);
sendToDP(shortDP, value);
}
});
}
// Popup öffnen/schließen
function openPopup() {
jalousiePopup.classList.add('active');
popupOverlay.style.display = 'block';
// Slider immer auf 0 setzen
sliderJalousie.value = 0;
sliderLamellen.value = 0;
// Value-Displays auf 0 setzen
popupJalousieValue.textContent = 0;
popupLamellenValue.textContent = 0;
// Status-Anzeige aus Datenpunkten lesen
if (typeof vis !== 'undefined') {
let jalousieStatus = vis.states.attr(statusJalousieDP + '.val');
let lamellenStatus = vis.states.attr(statusLamellenDP + '.val');
if (jalousieStatus !== undefined && jalousieStatus !== null) {
popupStatusJalousie.textContent = parseInt(jalousieStatus) + '%';
}
if (lamellenStatus !== undefined && lamellenStatus !== null) {
popupStatusLamellen.textContent = parseInt(lamellenStatus) + '%';
}
}
}
function closePopupFunc() {
jalousiePopup.classList.remove('active');
popupOverlay.style.display = 'none';
}
// Add touch event handlers to prevent background scrolling on mobile
document.getElementById('dg-buero-jalousie-popup-overlay').addEventListener('touchmove', function(e) {
e.preventDefault();
}, { passive: false });
document.getElementById('dg-buero-jalousie-popup').addEventListener('touchmove', function(e) {
// Only prevent if the touch is not on a slider
if (!e.target.classList.contains('jalousie-slider-vertical')) {
e.preventDefault();
}
}, { passive: false });
// Ensure sliders can be used on mobile
['dg-buero-slider-jalousie', 'dg-buero-slider-lamellen'].forEach(id => {
const slider = document.getElementById(id);
slider.addEventListener('touchmove', function(e) {
e.stopPropagation(); // Allow slider to function normally
}, { passive: true });
});
// Event-Listener für Popup
jalousieIcon.addEventListener('click', openPopup);
closePopup.addEventListener('click', closePopupFunc);
popupOverlay.addEventListener('click', closePopupFunc);
// Slider-Events mit Echtzeit-Aktualisierung
sliderJalousie.addEventListener('input', function() {
const value = parseInt(this.value);
popupJalousieValue.textContent = value;
});
sliderJalousie.addEventListener('change', function() {
const value = parseInt(this.value);
sendToDP(absoluteJalousieDP, value);
// Don't update statusValue directly since it comes from the datapoint
});
sliderLamellen.addEventListener('input', function() {
const value = parseInt(this.value);
popupLamellenValue.textContent = value;
// Also update the status bar immediately for better user feedback
popupStatusLamellen.textContent = value + '%';
});
sliderLamellen.addEventListener('change', function() {
const value = parseInt(this.value);
sendToDP(absoluteLamellenDP, value);
// The status will be updated via datapoint binding
});
// STOP-Button und Preset-Buttons
btnStop.addEventListener('click', function() {
sendToDP(lamellenDP, true);
});
btnPreset1.addEventListener('click', function() {
sendToDP(absoluteJalousieDP, 50);
});
btnPreset2.addEventListener('click', function() {
sendToDP(absoluteJalousieDP, 100);
});
// Setup popup arrow buttons with same logic as main widget
setupHoldButton(btnJalousieUp, lamellenDP, jalousienDP, false);
setupHoldButton(btnJalousieDown, lamellenDP, jalousienDP, true);
setupHoldButton(btnLamellenUp, lamellenDP, lamellenDP, false);
setupHoldButton(btnLamellenDown, lamellenDP, lamellenDP, true);
// Button-Konfiguration
setupHoldButton(btnUp, lamellenDP, jalousienDP, false);
setupHoldButton(btnDown, lamellenDP, jalousienDP, true);
// Initialisierung für ioBroker
function init() {
// Status-Wert überwachen
if (typeof vis !== 'undefined') {
// Jalousie-Status überwachen
vis.states.bind(statusJalousieDP + '.val', function(e, newVal, oldVal) {
if (newVal !== undefined) { // Prüfung hinzugefügt
jalousieValue = parseInt(newVal);
statusElement.textContent = jalousieValue;
sliderJalousie.value = jalousieValue;
if (popupJalousieValue) {
popupJalousieValue.textContent = jalousieValue;
}
if (popupStatusJalousie) {
popupStatusJalousie.textContent = jalousieValue + '%';
}
}
});
// Lamellen-Status überwachen
vis.states.bind(statusLamellenDP + '.val', function(e, newVal, oldVal) {
if (newVal !== undefined) {
lamellenValue = parseInt(newVal);
sliderLamellen.value = lamellenValue;
if (popupLamellenValue) {
popupLamellenValue.textContent = lamellenValue;
}
if (popupStatusLamellen) {
popupStatusLamellen.textContent = lamellenValue + '%';
}
}
});
// Anfangswerte laden
if (vis.states[statusJalousieDP + '.val'] !== undefined) {
jalousieValue = parseInt(vis.states[statusJalousieDP + '.val']);
statusElement.textContent = jalousieValue;
sliderJalousie.value = jalousieValue;
popupJalousieValue.textContent = jalousieValue;
popupStatusJalousie.textContent = jalousieValue + '%';
}
if (vis.states[statusLamellenDP + '.val'] !== undefined) {
lamellenValue = parseInt(vis.states[statusLamellenDP + '.val']);
sliderLamellen.value = lamellenValue;
popupLamellenValue.textContent = lamellenValue;
popupStatusLamellen.textContent = lamellenValue + '%';
}
} else {
// Fallback für Testumgebungen
jalousieValue = 50;
lamellenValue = 50;
statusElement.textContent = jalousieValue;
sliderJalousie.value = jalousieValue;
sliderLamellen.value = lamellenValue;
popupJalousieValue.textContent = jalousieValue;
popupLamellenValue.textContent = lamellenValue;
popupStatusJalousie.textContent = jalousieValue + '%';
popupStatusLamellen.textContent = lamellenValue + '%';
}
}
// Wenn vis bereits geladen ist
if (typeof vis !== 'undefined') {
init();
} else {
// Falls vis noch nicht geladen ist (sollte in ioBroker nicht passieren)
document.addEventListener('iobrokerReady', init);
}
</script>