Bonjour @tms ,
J'utilise ton flux Node-RED depuis quelques temps mais il me manquait des infos
J'ai donc modifié la fonction et ajouter une variable jeedom pour que le JSON soit interpréter par l'extension téléinfo de Jeedom
Pour le contexte j'ai un dongle Micro Teleinfo V3.0 sur la BananaPi dans mon garage sur lequel tourne une instance Node-RED et plutôt que de partager le port USB à ma VM Jeedom j'ai préféré mettre un place un flux qui publie le TIC en MQTT.
function computeChecksum(chars) {
// Calculer le checksum en additionnant les codes ASCII des caractères et en appliquant le masque
var sum = Array.from(chars).reduce((acc, curr) => acc + curr.charCodeAt(), 0);
return String.fromCharCode((sum & 0x3F) + 0x20); // Conversion en caractère ASCII
}
// Définir si le formatage pour Jeedom doit être appliqué
var jeedom = true; // Passe à false si le formatage n'est pas nécessaire
// Initialiser le payload
var payload = {
timestamp: new Date().getTime() // Ajouter un horodatage au payload
};
// Supprimer les caractères de début/fin de trame
var lines = msg.payload.toString().replace("\u0002\n", "").replace("\r\u0003", "");
// Traiter chaque ligne séparément
lines.split("\r\n").forEach(line => {
node.debug(`Ligne à décoder : ${line}`);
// Découper la ligne selon le format attendu : étiquette, horodatage, valeur, checksum
var groups = line.match(/^(.+?)\t(?:([\w\d]+)\t)?(.+)\t(.)$/i);
if (groups === null) {
node.warn(`Impossible de décoder la ligne '${line}'`);
} else {
var etiquette = groups[1].trim(); // Nom du champ
var valeur = groups[3].trim(); // Valeur associée
var checksum = groups[4].trim(); // Checksum reçu
// Calculer le checksum attendu
var computedChecksum = computeChecksum(line.slice(0, -1)); // Exclure le checksum reçu
if (computedChecksum !== checksum) {
node.warn(`Checksum invalide pour '${line}'. Attendu : '${computedChecksum}', reçu : '${checksum}'`);
return; // Ignorer cette ligne si le checksum est invalide
}
// Si l'étiquette est STGE, traiter la valeur comme un champ binaire
if (etiquette === 'STGE') {
let stgeValue = parseInt(valeur, 16).toString(2).padStart(32, '0'); // Compléter à 32 bits
// Décoder chaque groupe de bits avec les fonctions équivalentes
payload['STGE01'] = stgeValue[31] === '1' ? 'Ouvert' : 'Ferme';
payload['STGE02'] = switchMot02(parseInt(stgeValue.slice(28, 31), 2));
payload['STGE03'] = stgeValue[27] === '1' ? 'Ouvert' : 'Ferme';
payload['STGE04'] = switchMot04(parseInt(stgeValue[26], 2));
payload['STGE05'] = switchMot05(parseInt(stgeValue[25], 2));
payload['STGE06'] = switchMot06(parseInt(stgeValue[24], 2));
payload['STGE07'] = switchMot07(parseInt(stgeValue[23], 2));
payload['STGE08'] = switchMot08(parseInt(stgeValue[22], 2));
payload['STGE09'] = switchMot09(parseInt(stgeValue.slice(20, 22), 2));
payload['STGE10'] = switchMot10(parseInt(stgeValue.slice(18, 20), 2));
payload['STGE11'] = switchMot11(parseInt(stgeValue[17], 2));
payload['STGE12'] = switchMot12(parseInt(stgeValue[16], 2));
payload['STGE13'] = switchMot13(parseInt(stgeValue[15], 2));
payload['STGE14'] = switchMot14(parseInt(stgeValue.slice(13, 15), 2));
payload['STGE15'] = switchMot15(parseInt(stgeValue.slice(11, 13), 2));
payload['STGE16'] = switchMot16(parseInt(stgeValue[10], 2));
payload['STGE17'] = switchMot17(parseInt(stgeValue.slice(8, 10), 2));
payload['STGE18'] = switchMot18(parseInt(stgeValue.slice(6, 8), 2));
payload['STGE19'] = switchMot19(parseInt(stgeValue.slice(4, 6), 2));
payload['STGE20'] = switchMot20(parseInt(stgeValue.slice(2, 4), 2));
} else {
// Traitement normal pour les autres étiquettes
if (valeur.match(/^\d+$/)) {
valeur = parseInt(valeur);
}
payload[etiquette] = valeur;
}
}
});
// Fonctions de traduction (équivalents des switch_motXX en Python)
function switchMot01(argument) {
const map = {
0: "Ferme",
1: "Ouvert",
};
return map[argument] || "Invalide";
}
function switchMot02(argument) {
const map = {
0: "Ferme",
1: "Ouvert sur surpuissance",
2: "Ouvert sur surtension",
3: "Ouvert sur delestage",
4: "Ouvert sur ordre CPL ou Euridis",
5: "Ouvert sur surchauffe avec I > Imax",
6: "Ouvert sur surchauffe avec I < Imax",
};
return map[argument] || "Invalide";
}
function switchMot03(argument) {
const map = {
0: "Ferme",
1: "Ouvert",
};
return map[argument] || "Invalide";
}
function switchMot04(argument) {
const map = {
0: "Toujours à 0",
1: "Anormal",
};
return map[argument] || "Invalide";
}
function switchMot05(argument) {
const map = {
0: "Pas de surtension",
1: "Surtension",
};
return map[argument] || "Invalide";
}
function switchMot06(argument) {
const map = {
0: "Pas de dépassement",
1: "Dépassement en cours",
};
return map[argument] || "Invalide";
}
function switchMot07(argument) {
const map = {
0: "Consommateur",
1: "Producteur",
};
return map[argument] || "Invalide";
}
function switchMot08(argument) {
const map = {
0: "Énergie active positive",
1: "Énergie active négative",
};
return map[argument] || "Invalide";
}
function switchMot09(argument) {
const map = {
0: "Énergie ventilée sur Index 1",
1: "Énergie ventilée sur Index 2",
2: "Énergie ventilée sur Index 3",
3: "Énergie ventilée sur Index 4",
4: "Énergie ventilée sur Index 5",
5: "Énergie ventilée sur Index 6",
6: "Énergie ventilée sur Index 7",
7: "Énergie ventilée sur Index 8",
8: "Énergie ventilée sur Index 9",
9: "Énergie ventilée sur Index 10",
};
return map[argument] || "Invalide";
}
function switchMot10(argument) {
const map = {
0: "Énergie ventilée sur Index 1",
1: "Énergie ventilée sur Index 2",
2: "Énergie ventilée sur Index 3",
3: "Énergie ventilée sur Index 4",
};
return map[argument] || "Invalide";
}
function switchMot11(argument) {
const map = {
0: "Horloge correcte",
1: "Horloge en mode dégradé",
};
return map[argument] || "Invalide";
}
function switchMot12(argument) {
const map = {
0: "Mode Historique",
1: "Mode Standard",
};
return map[argument] || "Invalide";
}
function switchMot13(argument) {
const map = {
0: "Non utilisé",
1: "Non utilisé",
};
return map[argument] || "Invalide";
}
function switchMot14(argument) {
const map = {
0: "Désactivée",
1: "Activée sans sécurité",
2: "Invalide",
3: "Activée avec sécurité",
};
return map[argument] || "Invalide";
}
function switchMot15(argument) {
const map = {
0: "New/Unlock",
1: "New/Lock",
2: "Registered",
3: "Invalide",
};
return map[argument] || "Invalide";
}
function switchMot16(argument) {
const map = {
0: "Compteur non synchronisé",
1: "Compteur synchronisé",
};
return map[argument] || "Invalide";
}
function switchMot17(argument) {
const map = {
0: "Pas d'annonce",
1: "Bleu",
2: "Blanc",
3: "Rouge",
};
return map[argument] || "Invalide";
}
function switchMot18(argument) {
const map = {
0: "Pas d'annonce",
1: "Bleu",
2: "Blanc",
3: "Rouge",
};
return map[argument] || "Invalide";
}
function switchMot19(argument) {
const map = {
0: "Pas de préavis en cours",
1: "Préavis PM1 en cours",
2: "Préavis PM2 en cours",
3: "Préavis PM3 en cours",
};
return map[argument] || "Invalide";
}
function switchMot20(argument) {
const map = {
0: "Pas de pointe mobile",
1: "PM1 en cours",
2: "PM2 en cours",
3: "PM3 en cours",
};
return map[argument] || "Invalide";
}
// Ajouter le formatage pour Jeedom si nécessaire
if (jeedom) {
msg.payload = '{"TIC":' + JSON.stringify(payload) + '}';
msg.topic = 'teleinfo/TIC';
} else {
msg.payload = payload;
}
return msg;
C'est certainement perfectible en ajoutant par exemple un noeud réglages qui regrouperai les variables
Cordialement
Alexis