|
|
|
|
@ -148,6 +148,17 @@
@@ -148,6 +148,17 @@
|
|
|
|
|
color: white; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.mode-btn.secondary { |
|
|
|
|
background: #95a5a6; |
|
|
|
|
border-color: #95a5a6; |
|
|
|
|
color: white; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.mode-btn.secondary:hover { |
|
|
|
|
background: #7f8c8d; |
|
|
|
|
border-color: #7f8c8d; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.data-card.solar { |
|
|
|
|
background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%); |
|
|
|
|
} |
|
|
|
|
@ -233,6 +244,92 @@
@@ -233,6 +244,92 @@
|
|
|
|
|
flex-wrap: wrap; |
|
|
|
|
margin-top: 20px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-icon { |
|
|
|
|
display: inline-block; |
|
|
|
|
width: 24px; |
|
|
|
|
height: 24px; |
|
|
|
|
border-radius: 50%; |
|
|
|
|
background: #667eea; |
|
|
|
|
color: white; |
|
|
|
|
text-align: center; |
|
|
|
|
line-height: 24px; |
|
|
|
|
cursor: pointer; |
|
|
|
|
font-size: 16px; |
|
|
|
|
font-weight: bold; |
|
|
|
|
margin-left: 10px; |
|
|
|
|
transition: background 0.3s; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-icon:hover { |
|
|
|
|
background: #764ba2; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-modal { |
|
|
|
|
display: none; |
|
|
|
|
position: fixed; |
|
|
|
|
top: 0; |
|
|
|
|
left: 0; |
|
|
|
|
width: 100%; |
|
|
|
|
height: 100%; |
|
|
|
|
background: rgba(0, 0, 0, 0.6); |
|
|
|
|
z-index: 1000; |
|
|
|
|
justify-content: center; |
|
|
|
|
align-items: center; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-modal.show { |
|
|
|
|
display: flex; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-content { |
|
|
|
|
background: white; |
|
|
|
|
padding: 30px; |
|
|
|
|
border-radius: 10px; |
|
|
|
|
max-width: 600px; |
|
|
|
|
max-height: 80vh; |
|
|
|
|
overflow-y: auto; |
|
|
|
|
box-shadow: 0 10px 40px rgba(0,0,0,0.3); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-content h3 { |
|
|
|
|
color: #667eea; |
|
|
|
|
margin-top: 0; |
|
|
|
|
margin-bottom: 20px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-content .mode-item { |
|
|
|
|
margin-bottom: 20px; |
|
|
|
|
padding: 15px; |
|
|
|
|
background: #f5f7fa; |
|
|
|
|
border-radius: 5px; |
|
|
|
|
border-left: 4px solid #667eea; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-content .mode-title { |
|
|
|
|
font-weight: bold; |
|
|
|
|
font-size: 16px; |
|
|
|
|
color: #333; |
|
|
|
|
margin-bottom: 8px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.help-content .mode-desc { |
|
|
|
|
color: #555; |
|
|
|
|
line-height: 1.6; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.close-help { |
|
|
|
|
float: right; |
|
|
|
|
font-size: 28px; |
|
|
|
|
font-weight: bold; |
|
|
|
|
color: #aaa; |
|
|
|
|
cursor: pointer; |
|
|
|
|
line-height: 20px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.close-help:hover { |
|
|
|
|
color: #333; |
|
|
|
|
} |
|
|
|
|
</style> |
|
|
|
|
</head> |
|
|
|
|
<body> |
|
|
|
|
@ -291,7 +388,7 @@
@@ -291,7 +388,7 @@
|
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<h2>🎛️ Mode de Fonctionnement</h2> |
|
|
|
|
<h2>🎛️ Mode de Fonctionnement <span class="help-icon" onclick="toggleHelp()">?</span></h2> |
|
|
|
|
<div class="mode-selector"> |
|
|
|
|
<button class="mode-btn" data-bit="16" onclick="toggleMode(16)">🟢 ON</button> |
|
|
|
|
<button class="mode-btn" data-bit="8" onclick="toggleMode(8)">🌙 NUIT</button> |
|
|
|
|
@ -307,9 +404,92 @@
@@ -307,9 +404,92 @@
|
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<!-- Modal d'aide --> |
|
|
|
|
<div id="helpModal" class="help-modal" onclick="closeHelp(event)"> |
|
|
|
|
<div class="help-content" onclick="event.stopPropagation()"> |
|
|
|
|
<span class="close-help" onclick="toggleHelp()">×</span> |
|
|
|
|
<h3>📖 Guide des Modes de Chauffe</h3> |
|
|
|
|
|
|
|
|
|
<div class="mode-item"> |
|
|
|
|
<div class="mode-title">🟢 Mode ON</div> |
|
|
|
|
<div class="mode-desc"> |
|
|
|
|
Le chauffe-eau fonctionne à pleine puissance en permanence, indépendamment de la production solaire. |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="mode-item"> |
|
|
|
|
<div class="mode-title">🔴 Mode OFF</div> |
|
|
|
|
<div class="mode-desc"> |
|
|
|
|
Le chauffe-eau est complètement désactivé. Aucune chauffe n'est effectuée. |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="mode-item"> |
|
|
|
|
<div class="mode-title">🌙 Mode NUIT</div> |
|
|
|
|
<div class="mode-desc"> |
|
|
|
|
Active le chauffage entre <span id="nightHoursHelp">0h - 4h</span> pour atteindre |
|
|
|
|
la température minimale configurée de <span id="minTempHelp">40°C</span>.<br/>(Ces valeurs peuvent être modifiées dans les paramètres) |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="mode-item"> |
|
|
|
|
<div class="mode-title">☀️ Mode SOLEIL</div> |
|
|
|
|
<div class="mode-desc"> |
|
|
|
|
Utilise uniquement l'excédent de production solaire pour chauffer l'eau. La puissance de chauffe |
|
|
|
|
s'ajuste automatiquement en fonction de la production solaire disponible. Optimise l'autoconsommation. |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="mode-item"> |
|
|
|
|
<div class="mode-title">☼ Mode JOUR</div> |
|
|
|
|
<div class="mode-desc"> |
|
|
|
|
Chauffe intelligemment pendant les heures d'ensoleillement (lever à coucher du soleil) pour atteindre |
|
|
|
|
la température maximale configurée de<span id="maxTempHelp">60°C</span> à l'heure cible. La puissance est calculée en fonction du temps |
|
|
|
|
restant et de l'écart de température. Le chauffage s'arrête automatiquement une fois la température |
|
|
|
|
maximale atteinte jusqu'au lendemain. <em>(Le bouton devient gris quand la température max est atteinte)</em> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<div class="mode-item"> |
|
|
|
|
<div class="mode-title">🔄 Combinaisons</div> |
|
|
|
|
<div class="mode-desc"> |
|
|
|
|
Vous pouvez combiner les modes NUIT, SOLEIL et JOUR pour une gestion optimale : |
|
|
|
|
<ul style="margin: 10px 0 0 20px;"> |
|
|
|
|
<li><strong>NUIT + SOLEIL</strong> : Maintien nocturne + optimisation solaire diurne</li> |
|
|
|
|
<li><strong>NUIT + JOUR</strong> : Maintien nocturne + chauffe intelligente diurne</li> |
|
|
|
|
<li><strong>SOLEIL + JOUR</strong> : Utilise l'excédent + planifie la chauffe</li> |
|
|
|
|
<li><strong>NUIT + SOLEIL + JOUR</strong> : Combinaison complète pour un fonctionnement 24h/24</li> |
|
|
|
|
</ul> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<script> |
|
|
|
|
let refreshInterval; |
|
|
|
|
let currentMode = 0; // Mode par défaut (OFF) |
|
|
|
|
let configNightStart = 0; |
|
|
|
|
let configNightEnd = 4; |
|
|
|
|
let configMinTemp = 40; |
|
|
|
|
let configMaxTemp = 60; |
|
|
|
|
|
|
|
|
|
function toggleHelp() { |
|
|
|
|
const modal = document.getElementById('helpModal'); |
|
|
|
|
modal.classList.toggle('show'); |
|
|
|
|
// Mettre à jour les heures affichées dans le modal |
|
|
|
|
if (modal.classList.contains('show')) { |
|
|
|
|
document.getElementById('nightHoursHelp').textContent = |
|
|
|
|
configNightStart + 'h - ' + configNightEnd + 'h'; |
|
|
|
|
document.getElementById('minTempHelp').textContent = configMinTemp + '°C'; |
|
|
|
|
document.getElementById('maxTempHelp').textContent = configMaxTemp + '°C'; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function closeHelp(event) { |
|
|
|
|
if (event.target.id === 'helpModal') { |
|
|
|
|
toggleHelp(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function showError(message) { |
|
|
|
|
const statusDot = document.getElementById('statusDot'); |
|
|
|
|
@ -456,6 +636,29 @@
@@ -456,6 +636,29 @@
|
|
|
|
|
// Mettre à jour le flag global d'erreur Enphase |
|
|
|
|
window.enphaseConnectionError = !!data.enphase_connection_error; |
|
|
|
|
updateStatusBar(); |
|
|
|
|
|
|
|
|
|
// Mettre à jour les heures de configuration |
|
|
|
|
if (data.night_start_hour !== undefined) { |
|
|
|
|
configNightStart = data.night_start_hour; |
|
|
|
|
} |
|
|
|
|
if (data.night_end_hour !== undefined) { |
|
|
|
|
configNightEnd = data.night_end_hour; |
|
|
|
|
} |
|
|
|
|
if (data.min_water_temp !== undefined) { |
|
|
|
|
configMinTemp = data.min_water_temp; |
|
|
|
|
} |
|
|
|
|
if (data.max_water_temp !== undefined) { |
|
|
|
|
configMaxTemp = data.max_water_temp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Mettre à jour le style du bouton JOUR si maxTempReachedToday |
|
|
|
|
const jourBtn = document.querySelector('[data-bit="2"]'); |
|
|
|
|
if (data.max_temp_reached_today && jourBtn.classList.contains('active')) { |
|
|
|
|
jourBtn.classList.add('secondary'); |
|
|
|
|
} else { |
|
|
|
|
jourBtn.classList.remove('secondary'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
document.getElementById('dataDisplay').style.display = 'block'; |
|
|
|
|
|
|
|
|
|
// Mettre à jour la production solaire |
|
|
|
|
|