matter-history
Version:
Matterbridge history module
3 lines • 28.2 kB
JavaScript
import{colorStringify as t,historyStringify as a,id as e,rs as n,db as h,dn as l,wr as i,er as d,or as y}from"node-ansi-logger";import*as r from"fs";import s from"moment";import o from"assert";import g from"path";var m,f,u,E;(E=m=m||{})[E.BLANK=0]="BLANK",E[E.SUN=1]="SUN",E[E.CLOUDS_SUN=3]="CLOUDS_SUN",E[E.RAIN=5]="RAIN",E[E.RAIN_WIND=12]="RAIN_WIND",(E=f=f||{})[E.HIGH=0]="HIGH",E[E.MEDIUM=4]="MEDIUM",E[E.LOW=7]="LOW",(E=u=u||{})[E.CELSIUS=0]="CELSIUS",E[E.FAHRENHEIT=1]="FAHRENHEIT";class c{log;name;optionalParams;params;eveEpoch=978307200;initialTime=0;timeOffset=0;memorySize=0;firstEntry=0;currentEntry=-1;lastEntry=0;fileVersion="1.5";historyVersion="2.7.3";resetTotal=0;lastEvent=0;timesOpened=0;configData=Buffer.from("","hex");tlvConfigDataGet=[];tlvConfigDataSet=[];firmwareData=Buffer.from("","hex");historyLoaded=!1;historyDebug=!1;historyError=!1;historyClosed=!1;setRefTime=!1;historyWriting=!1;forceReloadHistoryStatus=!1;forceReloadHistoryRequest=!1;deviceOnline=!0;addResetTotal=!1;addLastEvent=!1;addTimesOpened=!1;addStatusFault=!1;statusFault=0;addStatusActive=!1;statusActive=!0;addFakeSwitch=!1;signature=Buffer.from("","hex");sigTable=[];tags=[{tag:1,length:2,factor:100,precision:2,entryName:"temperature"},{tag:2,length:2,factor:100,precision:2,entryName:"humidity"},{tag:3,length:2,factor:10,precision:0,entryName:"pressure"},{tag:6,length:1,factor:1,precision:0,entryName:"contact"},{tag:7,length:2,factor:10,precision:2,entryName:"consumption"},{tag:11,length:2,factor:10,precision:2,entryName:"power"},{tag:12,length:2,factor:10,precision:2,entryName:"voltage"},{tag:13,length:2,factor:100,precision:2,entryName:"current"},{tag:14,length:1,factor:1,precision:0,entryName:"status"},{tag:19,length:1,factor:1,precision:0,entryName:"motion"},{tag:23,length:1,factor:1,precision:0,entryName:"currentposition"},{tag:24,length:1,factor:1,precision:0,entryName:"targetposition"},{tag:25,length:1,factor:1,precision:0,entryName:"positionstate"},{tag:26,length:1,factor:1,precision:0,entryName:"obstructiondetected"},{tag:34,length:2,factor:1,precision:0,entryName:"voc"},{tag:36,length:1,factor:1,precision:0,entryName:"action"},{tag:40,length:1,factor:1,precision:0,entryName:"airquality"},{tag:48,length:2,factor:1,precision:0,entryName:"lux"}];tagsMap=new Map(this.tags.map(t=>[t.tag,t]));entryNameMap=new Map(this.tags.map(t=>[t.entryName,t]));historyLog;writingTimeout=void 0;historyFile="";queueTimeout=void 0;queuedEntries=[];toAverageEntries=[];lastValuesEntry={time:0};immediateKeys=["status","motion","contact","leak","smoke","action","currentposition","targetposition","positionstate","obstructiondetected"];averagedKeys=["consumption","power","voltage","current","lux","temperature","humidity","pressure","airquality","voc","co","co2","formaldehyd","pm10","pm25","lqi"];lastValueKeys=["contact"];averageTimer=null;constructor(t,e,i){this.log=t,this.name=e,this.optionalParams=i,this.params=Object.assign({enableDebug:!0,enableAutopilot:!1,enableConfigData:!1,historySize:4032,timerMinutes:10,fileName:e+"_history.json",filePath:"."},i),this.historyFile=this.params.filePath?g.join(this.params.filePath,this.params.fileName):this.params.fileName,this.memorySize=this.params.historySize,this.initialTime=this.now(),this.setRefTime=!0,this.historyLog={firstEntry:0,lastEntry:0,memorySize:this.memorySize,initialTime:this.initialTime,timeOffset:this.timeOffset,resetTotal:0,lastEvent:0,timesOpened:0,fileVersion:this.fileVersion,historyVersion:this.historyVersion,lastValues:this.lastValuesEntry,history:[{time:this.now(),setRefTime:4}],extra:void 0}}async close(){this.averageTimer&&clearInterval(this.averageTimer),this.averageTimer=null,this.queueTimeout&&clearInterval(this.queueTimeout),this.queueTimeout=void 0,this.writingTimeout&&clearTimeout(this.writingTimeout),this.writingTimeout=void 0,this.historyLoaded=!1,this.historyError=!0,this.historyClosed=!0}getInitialTime(){return this.historyLoaded?this.initialTime:(this.log.error("getInitialTime() called before history is loaded for "+e+this.name+n),this.now())}getTimeOffset(){return this.historyLoaded?this.timeOffset:(this.log.error("getTimeOffset() called before history is loaded for "+e+this.name+n),0)}getFirstEntry(){return this.firstEntry}getLastEntry(){return this.lastEntry}setDeviceOnline(t){this.deviceOnline=t}getLastEvent(){return this.lastEvent}setLastEvent(){this.lastEvent=this.now()-this.getInitialTime()}getTimesOpened(){return this.timesOpened}addToTimesOpened(){return this.timesOpened=this.timesOpened+1}getEntryAddress(t){return o(t>=this.firstEntry,d+`entry2address(${t}) error entry not >= firstEntry for `+l+this.name+n),o(t<=this.lastEntry,d+`entry2address(${t}) error entry not <= lastEntry for `+l+this.name+n),this.firstEntry,t%this.memorySize}getEntry(t){return this.historyLog.history[this.getEntryAddress(t)]}setEntry(t,e){this.historyLog.history[this.getEntryAddress(t)]=e}tlvConfigDataFields=[{field:0,type:1,name:"productId"},{field:3,type:2,name:"firmwareVersion"},{field:4,type:0,name:"serialNumber"},{field:32,type:1,name:">Status LED"},{field:96,type:1,name:"<Status LED"},{field:48,type:1,name:">LED on Motion"},{field:112,type:1,name:"<LED on Motion"},{field:113,type:2,name:"Lux"},{field:114,type:0,name:"<Only In Darkness"},{field:128,type:0,name:">Only In Darkness"},{field:11,type:2,name:"always0000"},{field:156,type:1,name:"always00"},{field:224,type:1,name:">CoverSpeed"},{field:240,type:1,name:">CoverSetPosition"},{field:242,type:1,name:">CoverSetup01"},{field:243,type:0,name:">CoverMoveUpDown"},{field:249,type:1,name:"always01"},{field:255,type:0,name:"threadstatus"},{field:208,type:4,name:"always00000000"},{field:68,type:0,name:"Schedule commands"},{field:69,type:0,name:"Schedule events"},{field:70,type:0,name:"Schedule days"},{field:71,type:0,name:"Schedule47"},{field:72,type:0,name:"Schedule48"},{field:73,type:0,name:"Schedule49"},{field:74,type:0,name:"Schedule4a"},{field:75,type:4,name:"WeatherMinMaxTemp"},{field:81,type:1,name:"Weather01"},{field:101,type:1,name:"ColorTempPowerOn"},{field:106,type:1,name:"TransitionA"},{field:107,type:1,name:"TransitionB"},{field:108,type:1,name:"TransitionC"},{field:177,type:2,name:"WeatherThermoConfig"},{field:210,type:0,name:"EndMarkWith0Length"}];tlvDataToValue(t,e){if(!t||0===e.length)return"";switch(t.field){case 4:return e.toString();case 75:return`Max temp: ${e.readUInt16LE()/100} Min temp: `+e.readUInt16LE(2)/100;case 114:return"0000ffff"===e.toString("hex")?"OFF":"Darkness Threshold "+e.readUInt16LE(2)}switch(t.type){case 1:return e.readUInt8();case 2:return e.readUInt16LE();case 4:return e.readUInt32LE();default:return""}}encodeConfigData(t){let e=Buffer.alloc(4096),i=0;return t.forEach(t=>{e.writeUInt8(t.field,i),i+=1,e.writeUInt8(t.length,i),i+=1,t.data.copy(e,i),i+=t.length}),e=e.subarray(0,i)}decodeConfigData(i,r=this.tlvConfigDataGet){let e=`ConfigData(${i.length}): [${i.toString("hex")}]`;for(let t=0;t<i.length;){let e=i.readUInt8(t);var s,o=i.readUInt8(t+1),a=Buffer.alloc(o),n=(i.copy(a,0,t+2,t+2+o),r.find(t=>t.field===e));n?(n.data.toString("hex")!==a.toString("hex")&&(n.updated=!0,s=this.tlvConfigDataFields.find(t=>t.field===e),n.value=this.tlvDataToValue(s,a)),n.length=o,n.data=a):(s=this.tlvConfigDataFields.find(t=>t.field===e),n=this.tlvDataToValue(s,a),r.push({field:e,name:s?s.name:"",length:o,data:a,updated:!1,value:n})),t+=o+2}return r.forEach(t=>{e+=`
field: ${t.field.toString(16).padStart(2,"0")} name: ${t.name.padEnd(20," ")} length: ${t.length.toString(10).padStart(2," ")} updated: ${t.updated} data: [${t.data.toString("hex")}]=`+t.value}),e}configDataToString(t){let e="configData:";return t.forEach(t=>{e+=`
field: ${t.field.toString(16).padStart(2,"0")} name: ${t.name.padEnd(20," ")} length: ${t.length.toString(10).padStart(2," ")} updated: ${t.updated} data: [${t.data.toString("hex")}]=`+t.value}),e}setMaxMinTemperature(t,e){this.log.debug("setMaxMinTemperature:",t,e),t=Math.ceil(t),e=Math.floor(e);var i=Buffer.from("4b0400000000","hex");i.writeUInt16LE(100*t,2),i.writeUInt16LE(100*e,4),this.decodeConfigData(i,this.tlvConfigDataGet),this.configData=this.encodeConfigData(this.tlvConfigDataGet),this.decodeConfigData(this.configData,this.tlvConfigDataGet)}decodeHistoryStatus(e){this.historyLoaded=!0;var t=1+2*e.readUInt8(12);this.signature=e.subarray(12,12+t);let i=0;this.sigTable=[];for(let t=0;t<e.readUInt8(12);t++){var r=e.readUInt8(13+2*t),r=(e.readUInt8(14+2*t),{tag:r,length:this.tagsMap.get(r).length,factor:this.tagsMap.get(r).factor,precision:this.tagsMap.get(r).precision,bitmask:Math.pow(2,i++),entryName:this.tagsMap.get(r).entryName});this.sigTable.push(r)}e.readUInt32LE(0),this.timeOffset=e.readUInt32LE(4),e.readUInt32LE(8);this.initialTime=e.readUInt32LE(8)+this.eveEpoch;var s=e.readUInt16LE(12+t);this.memorySize=e.readUInt16LE(14+t),this.firstEntry=e.readUInt32LE(16+t),e.readUInt32LE(20+t);return this.lastEntry=this.firstEntry+s-1,this.historyStatusToString(e)}encodeHistoryStatus(){this.forceReloadHistoryStatus&&this.log.warn("HistoryStatus forced reload"+n);var t=0;let e=Buffer.alloc(1024);return e.writeUInt32LE(Math.floor(Date.now()/1e3)-this.initialTime,0),t+=4,e.writeUInt32LE(this.timeOffset,4),t+=4,e.writeUInt32LE(this.initialTime-this.eveEpoch,8),t+=4,this.signature.copy(e,12),t+=this.signature.length,e.writeUInt16LE(this.forceReloadHistoryStatus?1:this.lastEntry-this.firstEntry+1,t),t+=2,e.writeUInt16LE(this.memorySize,t),t+=2,e.writeUInt32LE(this.firstEntry,t),t+=4,e.writeUInt32LE(this.historyLog.history[this.getEntryAddress(this.firstEntry)].time-this.initialTime,t),t+=4,e.writeUInt8(1,t),t+=1,e.writeUInt8(0,t),t+=1,e=e.subarray(0,t),this.forceReloadHistoryStatus=!1,e}historyStatusToString(t){var e=1+2*t.readUInt8(12),i=t.readUInt32LE(8),r=t.readUInt32LE(4);return"HistoryStatus: "+`[${t.toString("hex",0,4)}]${t.readUInt32LE(0)}=${this.secsToDateString(t.readUInt32LE(0)+this.eveEpoch+i-r)} `+`[${t.toString("hex",4,8)}]${t.readUInt32LE(4)} `+`[${t.toString("hex",8,12)}]${t.readUInt32LE(8)}=${this.secsToDateStringSinceEveEpoch(t.readUInt32LE(8)-r)} `+`[${t.toString("hex",12,12+e)}] `+`[${t.toString("hex",12+e,14+e)}]${t.readUInt16LE(12+e)} `+`[${t.toString("hex",14+e,16+e)}]${t.readUInt16LE(14+e)} `+`[${t.toString("hex",16+e,20+e)}]${t.readUInt32LE(16+e)} `+`[${t.toString("hex",20+e,24+e)}]${t.readUInt32LE(20+e)}=${this.secsToDateStringSinceEveEpoch(t.readUInt32LE(20+e)+i-r)} `+`[${t.toString("hex",24+e,25+e)}] `+`[${t.toString("hex",25+e,26+e)}]`}decodeHistoryEntry(e){e.readUInt8(0);var t=e.readUInt32LE(1),i=e.readUInt32LE(5);let r=e.readUInt8(9),s=10,o={time:i+this.initialTime-this.timeOffset};return 0<r&&r<128?this.sigTable.forEach(t=>{t.bitmask&r&&(console.log(`offset:${s} found bitmask:${t.bitmask.toString(2).padStart(8,"0")} tag: ${t.tag.toString(16).padStart(2,"0")} length:${t.length} factor:${t.factor} name:`+t.entryName),1===t.length?o[t.entryName]=e.readUInt8(s)/t.factor:2===t.length?o[t.entryName]=e.readInt16LE(s)/t.factor:4===t.length&&(o[t.entryName]=e.readInt32LE(s)/t.factor),s+=t.length)}):128<=r&&(o.setRefTime=r-128),console.log(a(o)),this.lastEntry=t,this.firstEntry=Math.max(0,this.lastEntry-this.memorySize+1),this.setEntry(t,o),this.historyEntryToString(e)}encodeHistoryEntry(t){let e=Buffer.alloc(1024,0),i=this.getEntry(t),r=10,s=0;return e.writeUInt32LE(t,1),e.writeUInt32LE(i.time-this.initialTime,5),Object.prototype.hasOwnProperty.call(i,"setRefTime")?(r=21,129===(s=128+i.setRefTime)&&e.writeUInt32LE(i.time-this.eveEpoch,10)):Object.entries(this.sigTable).forEach(([,t])=>{Object.prototype.hasOwnProperty.call(i,t.entryName)&&(1===t.length?e.writeUInt8(this.round(this.clamp(i[t.entryName]*t.factor,0,255),t.precision),r):2===t.length||3===t.length?e.writeInt16LE(this.round(this.clamp(i[t.entryName]*t.factor,-32768,32767),t.precision),r):4===t.length&&e.writeInt32LE(this.round(this.clamp(i[t.entryName]*t.factor,-2147483648,2147483647),t.precision),r),r+=t.length,s+=t.bitmask)}),e.writeUInt8(r,0),e.writeUInt8(s,9),e=e.subarray(0,r)}historyEntryToString(e){let t="HistoryEntry: "+`[${e.toString("hex",0,1)}]${e.readUInt8(0)} `+`[${e.toString("hex",1,5)}]${y}${e.readUInt32LE(1)}${h} `+`[${e.toString("hex",5,9)}]${e.readUInt32LE(5)}=${y}${this.secsToDateString(e.readUInt32LE(5)+this.initialTime-this.timeOffset)}${h} `+`[${e.readUInt8(9).toString(2).padStart(8,"0")}] `+`[${e.toString("hex",10,10+e.readUInt8(0))}]`,i=10;var r=e.readUInt32LE(5);let s=e.readUInt8(9),o={time:r+this.initialTime-this.timeOffset};return this.sigTable.forEach(t=>{t.bitmask&s&&0<s&&s<128&&(1===t.length?o[t.entryName]=e.readUInt8(i)/t.factor:2===t.length?o[t.entryName]=e.readInt16LE(i)/t.factor:4===t.length&&(o[t.entryName]=e.readInt32LE(i)/t.factor),i+=t.length)}),0<s&&s<128&&(t+="="+a(o)),128===e.readUInt8(9)&&(t+="=tag80"),129===e.readUInt8(9)&&(t+=e.readUInt32LE(10)+"="+this.secsToDateString(e.readUInt32LE(10)+this.eveEpoch)),132===e.readUInt8(9)&&(t+="=tag84"),t}historyEntriesToString(e){let i="HistoryEntries:";for(let t=0;t<e.length;){var r=Buffer.copyBytesFrom(e,t,e.readUInt8(t));t+=e.readUInt8(t),i+=` [${r.toString("hex")}]`}return i}decodeHistorySetTime(t){return this.setRefTime=!0,this.historySetTimeToString(t)}encodeHistorySetTime(t){var t=(void 0===t?Math.floor(Date.now()/1e3):t)-this.eveEpoch,e=Buffer.alloc(4);return e.writeUInt32LE(t),e}historySetTimeToString(t){return"HistorySetTime: "+`[${t.toString("hex",0,4)}]${t.readUInt32LE(0)}=`+this.secsToDateString(t.readUInt32LE(0)+this.eveEpoch)}decodeHistoryRequest(t){return this.currentEntry=this.clamp(t.readUInt32LE(2),this.firstEntry,this.lastEntry),this.forceReloadHistoryRequest&&(this.log.warn("HistoryRequest forced reload"+n),this.currentEntry=this.firstEntry,this.forceReloadHistoryRequest=!1),this.historyRequestToString(t)}encodeHistoryRequest(t){var e=Buffer.alloc(7);return e.writeUInt8(1,0),e.writeUInt8(255,1),e.writeUInt32LE(t,2),e.writeUInt8(0,6),e}historyRequestToString(t){return"HistoryRequest: "+`[${t.toString("hex",0,1)}] `+`[${t.toString("hex",1,2)}] `+`[${t.toString("hex",2,6)}]${t.readUInt32LE(2)} `+`[${t.toString("hex",6,7)}]`}signatureToString(){return t(this.sigTable)}addEntry(o){if(!0===this.historyClosed)this.log.error("addEntry(..) history already closed for "+e+this.name+n);else if(!0===this.historyError)this.log.error("addEntry(..) history file error so returns for "+e+this.name+n);else if(!1===this.historyLoaded)this.log.debug("addEntry() called before history is loaded: starting entries queue for "+l+this.name+n),this.queuedEntries.push(o),this.queueTimeout||(this.queueTimeout=setInterval(()=>{this.log.debug(`addEntry() queuedEntries interval: entries in the queue: ${this.queuedEntries.length} historyLoaded: ${this.historyLoaded} for `+l+this.name+n),this.queuedEntries.forEach((t,e)=>{this.log.debug(`addEntry() queuedEntry: ${e} - ${this.entryStringify(t)}${i} for `+l+this.name+n)}),this.historyLoaded&&(clearInterval(this.queueTimeout),this.queueTimeout=void 0,this.queuedEntries.forEach((t,e)=>{this.addEntry(t)}),this.queuedEntries.splice(0),this.log.debug("addEntry() queuedEntries interval: cleared entries queue for "+l+this.name+n))},1e3));else{this.log.debug(`addEntry() ${this.entryStringify(o)}${h} for `+l+this.name);let r={time:o.time},s={time:o.time};Object.entries(o).forEach(([t,e],i)=>{0===this.lastEntry||1===o.immediate?"immediate"!==t&&(r[t]=e):this.immediateKeys.includes(t)?e!==this.lastValuesEntry[t]?r[t]=e:this.log.debug(`addEntry() skipped key ${y}${t}${h}: ${y}${e}${h} since is not changed`):this.averagedKeys.includes(t)&&(s[t]=e)}),Object.assign(this.lastValuesEntry,o),delete this.lastValuesEntry.immediate,1<Object.keys(r).length&&this.addImmediateEntry(r),1<Object.keys(s).length&&this.addAveragedEntry(s)}}addAveragedEntry(t){!0===this.historyClosed?this.log.error("addAveragedEntry(..) history already closed for "+e+this.name+n):!1===this.historyLoaded?this.log.error("addAveragedEntry(..) called before history is loaded so returns for "+e+this.name+n):!0===this.historyError?this.log.error("addAveragedEntry(..) history file error so returns for "+e+this.name+n):(this.log.debug(`addAveragedEntry() ${this.entryStringify(t)}${h} for `+l+this.name),this.toAverageEntries.push(t))}addImmediateEntry(t){!0===this.historyClosed?this.log.error("addImmediateEntry(..) history already closed for "+e+this.name+n):!1===this.historyLoaded?this.log.error("addImmediateEntry(..) called before history is loaded so returns for "+e+this.name+n):!0===this.historyError?this.log.error("addImmediateEntry(..) history file error so returns for "+e+this.name+n):(this.log.debug(`addImmediateEntry() ${this.entryStringify(t)}${h} for `+l+this.name),!0===this.setRefTime&&(this.setRefTime=!1,this.lastEntry++,this.firstEntry=Math.max(0,this.lastEntry-this.memorySize+1),this.historyLog.history[this.getEntryAddress(this.lastEntry)]={time:t.time,setRefTime:1}),this.lastEntry++,this.firstEntry=Math.max(0,this.lastEntry-this.memorySize+1),this.historyLog.history[this.getEntryAddress(this.lastEntry)]=t,this.writeHistoryFile())}averageTimerStart(t){null===this.averageTimer&&0<this.params.timerMinutes&&(t&&this.averageTimerCallback(),this.averageTimer=setInterval(()=>{this.averageTimerCallback()},60*this.params.timerMinutes*1e3))}averageTimerCallback(){this.log.debug(`averageTimerCallback() started with ${this.toAverageEntries.length} entries for `+l+this.name+n),this.toAverageEntries.forEach(t=>{this.log.debug("-- entry: "+this.entryStringify(t))});var t,e={time:this.now()};for(t in this.lastValuesEntry)this.lastValueKeys.includes(t)&&void 0!==this.lastValuesEntry[t]&&(e[t]=this.lastValuesEntry[t]);1<Object.keys(e).length&&(this.log.debug(`Average timer lastValues result: ${this.entryStringify(e)} for `+l+this.name+n),this.addImmediateEntry(e));let i={},r={};this.toAverageEntries.forEach(t=>{for(var e in t)"time"!==e&&(i[e]=(i[e]||0)+t[e],r[e]=(r[e]||0)+1)}),this.log.debug(`Last values: ${this.entryStringify(this.lastValuesEntry)} for `+l+this.name+n);var s,o,a={time:this.now()};for(s in this.lastValuesEntry)this.averagedKeys.includes(s)&&void 0!==this.lastValuesEntry[s]&&(a[s]=this.lastValuesEntry[s]);for(o in i)a[o]=this.round(i[o]/r[o],void 0!==this.entryNameMap.get(o)?this.entryNameMap.get(o).precision:0);1<Object.keys(a).length&&(this.log.debug(`Average timer result: ${this.entryStringify(a)} for `+l+this.name+n),this.addImmediateEntry(a)),this.toAverageEntries=[]}logHistory(s=!1){if(!0===this.historyClosed)this.log.error("logHistory(..) history already closed for "+e+this.name+n);else{this.log.debug("History log for "+e+this.name+n),this.log.debug("enableDebug*:",this.params.enableDebug),this.log.debug("enableAutopilot*:",this.params.enableAutopilot),this.log.debug("enableConfigData*:",this.params.enableConfigData),this.log.debug("historySize*:",this.params.historySize),this.log.debug("fileName*:",this.params.fileName),this.log.debug("filePath*:",this.params.filePath),this.log.debug("timerMinutes*:",this.params.timerMinutes),this.log.debug("historyFile: "+this.historyFile),this.log.debug("historyLoaded: "+this.historyLoaded),this.log.debug("historyError: "+(this.historyError?d:h)+this.historyError),this.log.debug("historyTimer: "+this.averageTimer),this.log.debug("setRefTime: "+this.setRefTime),this.log.debug("historyWriting: "+this.historyWriting),this.log.debug("firstEntry: "+this.firstEntry),this.log.debug("lastEntry: "+this.lastEntry),this.log.debug("memorySize: "+this.memorySize),this.log.debug(`initialTime: ${this.initialTime} `+this.secsToDateString(this.initialTime)),this.log.debug("fileVersion: "+this.historyLog.fileVersion),this.log.debug("historyVersion: "+this.historyLog.historyVersion),this.log.debug("lastValues: "+this.entryStringify(this.lastValuesEntry)),this.addResetTotal?this.log.debug(`resetTotal: ${this.addResetTotal} ${this.resetTotal} (${this.secsToDateStringSinceEveEpoch(this.resetTotal)})`):this.log.debug("resetTotal: "+this.addResetTotal),this.addLastEvent?this.log.debug(`lastEvent: ${this.addLastEvent} ${this.lastEvent} (${this.diffToString(this.now()-this.lastEvent-this.getInitialTime())})`):this.log.debug("lastEvent: "+this.addLastEvent),this.addTimesOpened?this.log.debug(`timesOpened: ${this.addTimesOpened} `+this.timesOpened):this.log.debug("timesOpened: "+this.addTimesOpened),this.log.debug("toAverageEntries: "+this.toAverageEntries.length),0<this.toAverageEntries.length&&this.toAverageEntries.forEach((t,e)=>{this.log.debug(` ${e} `+this.entryStringify(t)+n)}),this.log.debug("entries: "+this.historyLog.history.length),0<this.historyLog.history.length&&(this.log.debug("first entry: "+this.entryStringify(this.historyLog.history[this.getEntryAddress(this.firstEntry)])),this.log.debug("last entry: "+this.entryStringify(this.historyLog.history[this.getEntryAddress(this.lastEntry)])));let i=!1,r=!1;if(this.log.debug(`signature table length ${this.sigTable.length}:`),this.sigTable.forEach((t,e)=>{this.log.debug(` ${e} - `+this.entryStringify(t)+n),i=i||this.immediateKeys.includes(t.entryName),r=r||this.averagedKeys.includes(t.entryName)}),this.log.debug(`signature: [${y}${this.signature.toString("hex")}${n}${h}]`),this.log.debug(`configData: [${y}${this.configData.toString("hex")}${n}${h}]`),0!==this.initialTime){let e=this.historyLog.history[this.getEntryAddress(this.firstEntry)].time;for(let t=this.firstEntry;t<=this.lastEntry;t++){var o=this.getEntry(t);o.time<e&&this.log.error(`Entry: ${t.toString().padStart(4," ")} ${this.entryStringify(o)}${d} is out of order`+n),r&&void 0===o.setRefTime&&600<o.time-e&&this.log.error(`Entry: ${t.toString().padStart(4," ")} ${this.entryStringify(o)}${d} is after ${Math.round((o.time-e)/60*100)/100} minutes `+n),1===Object.keys(o).length&&this.log.error(`Entry: ${t.toString().padStart(4," ")} ${this.entryStringify(o)}${d} is only time`+n),!0===s&&this.log.debug(`Entry: ${t.toString().padStart(4," ")} `+this.entryStringify(o)+n),e=o.time}}}}readHistoryFile(a){if(!0===this.historyClosed)this.log.error("readHistoryFile(..) history already closed for "+e+this.name+n);else{let i=!1,s=!1,o=!1;this.sigTable.forEach((t,e)=>{i=i||this.immediateKeys.includes(t.entryName),s=s||this.averagedKeys.includes(t.entryName),o=o||this.lastValueKeys.includes(t.entryName)}),r.readFile(this.historyFile,"utf8",(t,i)=>{if(t)"ENOENT"===t.code?(this.log.debug(`History file ${this.historyFile} doesn't exist. Ready to write it.`),this.historyLoaded=!0,(s||o)&&this.averageTimerStart(!1),a?.(!0)):(this.log.error(`Error reading from file ${this.historyFile}:`,t),this.historyLoaded=!1,this.historyError=!0,a?.(!1));else try{this.historyLog=JSON.parse(i),this.firstEntry=this.historyLog.firstEntry,this.lastEntry=this.historyLog.lastEntry,this.memorySize=this.historyLog.memorySize,this.initialTime=this.historyLog.initialTime,this.timeOffset=this.historyLog.timeOffset,this.lastValuesEntry=this.historyLog.lastValues,this.lastEvent=this.historyLog.lastEvent,this.resetTotal=this.historyLog.resetTotal,this.timesOpened=this.historyLog.timesOpened,this.historyLog.fileVersion===this.fileVersion&&this.historyLog.historyVersion===this.historyVersion||(this.log.debug(`*Preparing to update historyFile from fileVersion: ${this.historyLog.fileVersion} to fileVersion: ${this.fileVersion} from historyVersion: ${this.historyLog.historyVersion} to historyVersion: ${this.historyVersion} for `+l+this.name+n),this.timeOffset=0,this.historyLog.timeOffset=0,this.lastEntry+1<=this.memorySize&&(this.firstEntry=0,this.historyLog.history[this.getEntryAddress(this.firstEntry)]={time:this.initialTime,setRefTime:4}),this.writingTimeout=setTimeout(()=>{this.writeHistoryFile()},1e4)),this.log.debug(`History loaded with ${y}${this.historyLog.firstEntry}${h}-${y}${this.historyLog.lastEntry}${h} entries for `+l+this.name+n);let e=this.historyLog.history[this.getEntryAddress(this.firstEntry)].time;for(let t=this.firstEntry;t<=this.lastEntry;t++){var r=this.historyLog.history[this.getEntryAddress(t)];r.time<e?this.log.error(`Entry: ${t.toString().padStart(4," ")} ${this.entryStringify(r)}${d} is out of order`+n):s&&void 0===r.setRefTime&&630<r.time-e&&this.log.debug(`Entry: ${t.toString().padStart(4," ")} ${this.entryStringify(r)}${d} is after ${Math.round((r.time-e)/60*100)/100} minutes `+n),1===Object.keys(r).length&&this.log.error(`Entry: ${t.toString().padStart(4," ")} ${this.entryStringify(r)}${d} is only time`+n),e=r.time}this.historyLoaded=!0,(s||o)&&this.averageTimerStart(!1),a?.(!0)}catch(t){this.log.error(`Error parsing JSON from file ${this.historyFile}:`,t),this.historyLoaded=!1,this.historyError=!0,a?.(!1)}})}}writeHistoryFile(){if(!0===this.historyClosed)this.log.error("writeHistoryFile(..) history already closed for "+e+this.name+n);else if(!1===this.historyLoaded)this.log.error("writeHistoryFile(..) called before history is loaded for "+e+this.name+n);else if(this.log.debug("writeHistoryFile() for "+l+this.name+n),this.historyWriting)this.log.debug("writeHistoryFile() writing already in progress. Retry in 500 ms."+n),void 0!==this.writingTimeout&&clearTimeout(this.writingTimeout),this.writingTimeout=setTimeout(()=>{this.writeHistoryFile()},500);else{if(this.historyWriting=!0,this.historyLog.firstEntry=this.firstEntry,this.historyLog.lastEntry=this.lastEntry,this.historyLog.memorySize=this.memorySize,this.historyLog.initialTime=this.initialTime,this.historyLog.timeOffset=this.timeOffset,this.historyLog.lastValues=this.lastValuesEntry,this.historyLog.resetTotal=this.resetTotal,this.historyLog.lastEvent=this.lastEvent,this.historyLog.timesOpened=this.timesOpened,this.historyLog.fileVersion!==this.fileVersion||this.historyLog.historyVersion!==this.historyVersion)try{r.unlinkSync(this.historyFile),this.historyLog.fileVersion=this.fileVersion,this.historyLog.historyVersion=this.historyVersion,delete this.historyLog.usedMemory,delete this.historyLog.refTime,delete this.historyLog.totalMemory,delete this.historyLog.referenceTime,delete this.historyLog.memoryUsed,this.timeOffset=0,this.historyLog.timeOffset=0,this.lastEntry+1<=this.memorySize&&(this.firstEntry=0,this.historyLog.history[this.getEntryAddress(this.firstEntry)]={time:this.initialTime,setRefTime:4}),this.log.debug(`*Successfully updated historyFile to fileVersion: ${this.historyLog.fileVersion} historyVersion: ${this.historyLog.historyVersion} for `+l+this.name+n)}catch(t){this.log.error(`Error updating historyFile ${this.historyFile}:`,t)}var t=JSON.stringify(this.historyLog);r.writeFile(this.historyFile,t,"utf8",t=>{t?(this.log.error(`Error writing to file ${this.historyFile}:`,t),this.historyLoaded=!1,this.historyError=!0):(this.log.debug("Successfully wrote historyFile for "+l+this.name+n),this.historyLoaded=!0,this.historyWriting=!1)})}}entryStringify(t){let s=n+"{ ";return Object.entries(t).forEach(([t,e],i)=>{0<i&&(s+=", ");let r="";"boolean"==typeof(r="number"==typeof(r="string"==typeof(r="time"===t?this.secsToDateString(e):"bitmask"===t?"0b"+e.toString(2).padStart(8,"0"):"tag"===t?"0x"+e.toString(16).padStart(2,"0"):e)?"[38;5;35m'"+r+"'[0m":r)?"[38;5;220m"+r+"[0m":r)&&(r="[38;5;159m"+r+"[0m"),s+=""+y+t+n+": "+r}),s+=" }"+n}diffToString(t){var e=s.duration(t,"seconds");let i;return i=1<=e.asDays()?Math.round(e.asDays())+" days":1<=e.asHours()?Math.round(e.asHours())+" hours":1<=e.asMinutes()?Math.round(e.asMinutes())+" minutes":t+" seconds"}secsToDateString(t){return s.unix(t).format("DD-MM-YYYY HH:mm:ss")}secsToDateStringSinceEveEpoch(t){return this.secsToDateString(t+this.eveEpoch)}now(){return s().unix()}clamp(t,e,i){return Math.min(Math.max(t,e),i)}round(t,e){function i(t,e,i){return i&&(e=-e),+((i=(""+t).split("e"))[0]+"e"+(i[1]?+i[1]+e:e))}return i(Math.round(i(t,e,!1)),e,!0)}getFakeLevel(t,e,i=0){let r=0;return r=this.secondsSinceNoon()>this.secondsSinceMidnight()?t+(e-t)*this.secondsSinceMidnight()/43200:e-(e-t)*this.secondsSinceNoon()/43200,this.round(r,i)}secondsSinceMidnight(){var t=new Date,e=new Date(t.getFullYear(),t.getMonth(),t.getDate());return Math.round((+t-+e)/1e3)}secondsSinceNoon(){var t=new Date,e=new Date(t.getFullYear(),t.getMonth(),t.getDate(),12,0,0),t=(t<e&&e.setDate(e.getDate()-1),(+t-+e)/1e3);return Math.round(t)}}export{m as WeatherTrend,f as Sensitivity,u as TemperatureDisplayUnits,c as History};