Hallo ruhr!
Kein Problem, können/sollen auch sehr wohl Fragen gestellt werden! Man ist ja selbst immer 'betriebsblind'.
Nach der kleinen Zwangspause gehts weiter.
Habe eins vergessen: Wie schaut ihr welche Node-Version ihr habt?
mit node -v geht das ganz leicht.
Hatte gestern einen Raspi 3 mit dem neuen Jessie-Image von letzter Woche gestartet und war geschockt dass da noch 0.10.irgendwas dabei war. Das wird in einigen Wochen nicht mehr supported!
Um am Raspi (oder anderen Debian Linux) ein neueres node zu installieren lädt man die nodesource mit
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
oder
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
sudo apt-get install nodejs
Die 6er ist die letztgültige Long-Time-Support-Version (Boron). Es gibt auch 7er aber das ist nur für developers da sie nach Erscheinen der 8ter (nächstes halbes Jahr) dann nicht mehr supported werden.
Unter Windows rate ich auf https://nodejs.org/de/download/ sich die letzte oder andere Versionen wie 4.6.x dort zu suchen https://nodejs.org/en/download/releases/.
Ja, so machen wir mal weiter. In vielen Scripten muss man Variablen anlegen.
Ich habe mir das so angewöhnt:
function createStates () { "use strict"; // Die Funktion returniert eine Promise damit sie verschachtelt werden kann!, 'use strict' erlaubt verwendung von let usw.
_D("Create States");
const states = [ // Ich kreiere eine objekt-Array mit allen zu erzeugenden Objekten
{ id: alarm, val: false, common: {type: 'boolean',name:alarm, unit: '',role: 'state',write:true}},
{ id: alarmPot, val: "", common: {type: 'string',name:alarmPot, unit: '',role: 'state',write:true}},
{ id: alarmState, val: 0, common: {type: 'number',name:alarmState, unit: '',role: 'state',write:true,max:2,min:0,states:'0:Aus;1:Nacht;2:Ein'}},
];
for (let i=0; i<3;i++) // muss 3 Variablem programmatisch anlegen, können ja auch von aussen kommen
states.push({ id: dpPfad+'Var_'+i , val: i, common: {type: 'number',name:`${dpPfad}Variable ${i}`, unit: '',role: 'state',write:true}});
return pSeries(states, (item) => pCst(item.id,item.val,item.common,{}).then(() => item.id), 10) // cSt ist die in Promise umgewandelte Form von createState, ruft pSeries ruft es für jedes array-item auf und fügt zwischen den items 10ms Pause ein
.then(x => wait(100,_D('end created states:'+_O(x),x))); // am Ende wird die Liste der angelegten ID's ausgegeben und 100ms gewartet
}
Damit erzeuge ich erstmals ein array von Objekten die die Variablen beschreiben, entweder hard-coded oder programmatisch und dann kreiere ich alle Variablen mittels pSeries.
pSeries(iterable, functionPromise, delay) durchläuft die iterable (kann ein Objekt oder Array sein) und ruft functionPromis(item) für jedes item auf. Die Funktion muß eione Promise zurückgeben. Falls delay angegeben wird wird so viele ms gewartet und dann (sonst sofort) das nächste item aufgerufen.
der Teil '(item) => pCst(item.id,item.val,item.common,{}).then(() => item.id)' verwendet die umgewandelte createState und gibt eine id and pSeries zurück.
pSeries sammelt alle returnbieren Arguimente und wenn es durch ist giebt sie al array zurück.
Damit kann '.then(x =>…' dieses Array anzeigen, warten und selbst dann zurückgegeben werden.
Am Ende unseres scripts steht die Folge:
wait(100)
.then(() => createStates())
.then(() => onAnlegen()) // ist ähnlich wie createStates aufgebaut.
.then(() => main()) // test functions
.catch(error => _W(_O(error))) // war da ein Fehler?
.then(() => _I(`Finished Initialization and running ${instanz}${name}`));
Damit wird beim Start des scriptes zuerst 100ms gewartet, dann dies Variablen kreiert, dann onAnlegen ausgeführt, dann main ausgeführte, dann auf eventuellen Fehlern in einigen der vorigen Routinen geprüft und dann die info ausgegeben dass das Script jetzt läuft!
Was kann man sonst noch machen?
Ich zeig mal ein Beispiel welches fast gleich ich einen Adapter eingeflossen ist (hab dort nur einen cache eingebaut um nicht alle x Sekunden das selbe abzufragen):
arp-scan kann unter linux mit sudo apt-get install arp-scan installiert werden uns scannt das lokale Netz nach angeschlossenen/laufenden Geräten.
const dns = require('dns'); // inkludiere die 'dns'-funktionen
pExec('arp-scan -lgq --retry=10') // rufe arp-scan auf
.then(res => res && res.match(/(\d*\.){3}\d*\s*([\dA-F]{2}\:){5}[\dA-F]{2}/gi)) // gib ein Array aus die aus den IP und MAC-Adressen besteht die gefunden wurden
.then(res => pSeries(res, item => { // Für jedes gefundene IP/MAC-Paar
const s = item.split('\t'); // splitte die IP von der MAC-Adresse, diese sind durch \t getrennt
return pGet('http://api.macvendors.com/'+s[1]) // nun prüfe mittels einer web-Api wer der Erzeuge für die HW ist mit dieser Mac-Adresse
.then(x => x.trim(), err => 'Vendor not found') // wenn ein Fehler auftritt und der Hersteller nicht gefunden wird gib 'Vendor not found' zurück
.then(x => s.push(x) && c2pP(dns.reverse)(s[0])) // hänge an das split array den Herstellernamen an und versuche einen dns.reverse call mit der IP-Adresse um den Namen am lokalen DNS-Server zu erfahren
.then(nam => s.concat(nam), err => s.concat(['N/A'])) // Hänge den Namen oder 'N/A' an wenn er nicht gefunden wurde
.then(res => res.join('; ')); // Mach aus dem Array ein String mit '; ' getrennt
},10)) // warte 10ms nach jedem gefundenen Paar
.then(res => pSeries(res,item => _D(_O(item),Promise.resolve()))); // Zeig alle Ergebnisse an. Promise.resolve returniert eine Promise die sofort 'Erfolg' bestätigt.
Warum verwende ich lieber const/let? Es reduziert die Proigrammierfehler!
Mit const s = xxx sag ich dass ich s diesen Block definiere und es nicht neu zugewiesen werden darf.
Mit s.push() kann ich den Inhalt veändern aber ich darf s nich mit s = x neu zuweisen.
Mit let definiert man variablen die auch nur in diesem Block gültig sind, also ist
`var k = [1,2,3];
for (let i in k) {
let j = k[i];
for(let k of [11,22,33])
_D(`${k}:${j}`);
}
_D(k);`
immer eine neue Variable i,j und k und das 'var k' bleibt so wie es ist.
Aber Vorsicht: Wenn ihr Node Version 4.x oder darunter (0.12) verwendet ist let nur anwendbar wenn '"use strict";' auf Funktionslevel angewendet wird.
Wenn ihr Version 6.9.x verwendet (die momentane Note-LTS = Long Time Support-Version) dann ist let auch im gesamten schript ohne '"use strict";' möglich.
In einer weiteren Folge weden wir dann einige weiteren Tricks beleuchten!
Liebe Grüße
Frank[/i]