bt-sensors-plugin-sk 1.2.0-beta.0.1.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,15 @@ object-assign
10
10
  http://jedwatson.github.io/classnames
11
11
  */
12
12
 
13
+ /*!
14
+ * The buffer module from node.js, for the browser.
15
+ *
16
+ * @author Feross Aboukhadijeh <https://feross.org>
17
+ * @license MIT
18
+ */
19
+
20
+ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
21
+
13
22
  /**
14
23
  * @license React
15
24
  * react-is.production.min.js
package/public/847.js ADDED
@@ -0,0 +1 @@
1
+ (self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[]).push([[847],{9337:()=>{},62995:(e,t,n)=>{"use strict";n.r(t),n.d(t,{default:()=>k});var a=n(73490),o=n(74810),s=n(86528),r=n.n(s),l=n(40334),c=n(27606),i=n(86452),u=n(82096),g=n(3768),d=n(71431),m=n(39676),f=n(47041),h=n(86038),p=n(95027),E=n(43540),w=n(38250),y=n(31008),v=n(20455),S=n(23399);const b=e=>console.log.bind(console,e);var A,D={};function k(e){const t=(0,u.A)((e=>({root:{"& > *":{margin:e.spacing(1)}}}))),[n,k]=(0,s.useState)({}),[C,_]=(0,s.useState)({}),[x,$]=(0,s.useState)({}),[T,N]=(0,s.useState)({"ui:options":{label:!1},title:{"ui:widget":"hidden"}}),[j,M]=(0,s.useState)([]),[O,U]=(0,s.useState)(),[L,J]=(0,s.useState)(new Map),[B,I]=(0,s.useState)({progress:0,maxTimeout:100,deviceCount:0,totalDevices:0}),[P,R]=(0,s.useState)("unknown"),[G,H]=(0,s.useState)(),K=t();function F(e,t){console.log(`sending ${e}`),console.log(t);const n=new Headers;return n.append("Content-Type","application/json"),fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include",method:"POST",body:JSON.stringify(t),headers:n})}async function W(e){var t;console.log(`fetching ${e}`);try{t=fetch(`/plugins/bt-sensors-plugin-sk/${e}`,{credentials:"include"})}catch(e){t={status:500,statusText:e.toString()}}return t}function Y(e){return Object.keys(e.config).length>0}function q(e){const t=Y(e);return r().createElement(v.A,{action:!0,onClick:()=>{e.config.mac_address=e.info.mac,$(e.schema),U(e.config)}},r().createElement("div",{class:"d-flex justify-content-between align-items-center",style:t?{fontWeight:"normal"}:{fontStyle:"italic"}},`${e._changesMade?"*":""}${e.info.name} MAC: ${e.info.mac} RSSI: ${n=e.info.RSSI,null==n?NaN:n}`,r().createElement("div",{class:"d-flex justify-content-between "},function(e){return null==e.info.lastContactDelta||e.info.lastContactDelta>e.config.discoveryTimeout?r().createElement(g.A,null):e.info.signalStrength>80?r().createElement(d.A,null):e.info.signalStrength>60?r().createElement(m.A,null):e.info.signalStrength>40?r().createElement(f.A,null):e.info.signalStrength>20?r().createElement(h.A,null):r().createElement(p.A,null)}(e))));var n}function z(e){window.open(e,"_blank","noreferrer")}return(0,s.useEffect)((()=>{console.log("useEffect([])");let e=null;return W("getPluginState").then((async t=>{if(404==t.status)throw R("unknown"),new Error("unable to get plugin state");const n=await t.json();console.log("Setting up eventsource"),e=new EventSource("/plugins/bt-sensors-plugin-sk/sse",{withCredentials:!0}),R(n.state),await async function(){console.log("getDomains");const e=await W("getDomains");if(200!=e.status)throw new Error(`Unable get domain data: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}(),e.addEventListener("newsensor",(e=>{console.log("newsensor");let t=JSON.parse(e.data);A.has(t.info.mac)||(console.log(`New sensor: ${t.info.mac}`),J(new Map(A.set(t.info.mac,t))))})),e.addEventListener("sensorchanged",(e=>{let t=JSON.parse(e.data);if(console.log("sensorchanged"),console.log(t),A.has(t.mac)){let e=A.get(t.mac);Object.assign(e.info,t),J(new Map(A))}})),e.addEventListener("progress",(e=>{console.log("progress");const t=JSON.parse(e.data);I(t),console.log(t)})),e.addEventListener("pluginstate",(e=>{console.log("pluginstate");const t=JSON.parse(e.data);R(t.state)}))})).catch((e=>{H(e)})),()=>{console.log("Closing connection to SSE"),e.close()}}),[]),(0,s.useEffect)((()=>{console.log("useEffect([pluginState])"),"started"==P?(console.log("refreshing sensor map"),async function(){console.log("getSensors");const e=await W("getSensors");if(200!=e.status)throw new Error(`Unable get sensor data: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}().then((e=>{J(new Map(e.map((e=>[e.info.mac,e]))))})).catch((e=>{H(e)})),async function(){console.log("getBaseData");const e=await W("getBaseData");if(200!=e.status)throw new Error(`Unable to get base data: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t.schema.htmlDescription=r().createElement("div",null,(0,l.Ay)(t.schema.htmlDescription),r().createElement("p",null)),t}().then((e=>{k(e.schema),_(e.data)})).catch((e=>{H(e)})),async function(){console.log("getProgress");const e=await W("getProgress");if(200!=e.status)throw new Error(`Unable to get progress: ${e.statusText} (${e.status}) `);const t=await e.json();return console.log(t),t}().then((e=>{I(e)})).catch((e=>{H(e)}))):(J(new Map),k({}),_({}))}),[P]),(0,s.useEffect)((()=>{console.log("useEffect([sensorMap])"),A=L;const e=new Set(L.entries().map((e=>e[1].info.domain))),t={_configured:Array.from(L.entries()).filter((e=>Y(e[1]))).map((e=>q(L.get(e[0]))))};e.forEach((e=>{var n;t[e]=(n=e,Array.from(L.entries()).filter((e=>e[1].info.domain===n))).map((e=>q(L.get(e[0]))))})),D=t}),[L]),"stopped"==P||"unknown"==P?r().createElement("h3",null,"Enable plugin to see configuration"):r().createElement("div",null,r().createElement("div",{className:K.root},r().createElement(i.A,{variant:"contained",onClick:()=>{z("https://github.com/naugehyde/bt-sensors-plugin-sk/tree/1.2.0-beta#configuration")}},"Documentation"),r().createElement(i.A,{variant:"contained",onClick:()=>{z("https://github.com/naugehyde/bt-sensors-plugin-sk/issues/new/choose")}},"Report Issue"),r().createElement(i.A,{variant:"contained",onClick:()=>{z("https://discord.com/channels/1170433917761892493/1295425963466952725")}},"Discord Thread"),r().createElement("p",null),r().createElement("p",null)),r().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),G?r().createElement("h2",{style:"color: red;"},G):"",r().createElement(a.Ay,{schema:n,validator:o.Ay,uiSchema:{"ui:field":"LayoutGridField","ui:layoutGrid":{"ui:row":[{"ui:row":{className:"row",children:[{"ui:columns":{className:"col-xs-4",children:["adapter","transport","duplicateData","discoveryTimeout","discoveryInterval"]}}]}}]}},onChange:e=>_(e.formData),onSubmit:({formData:e},t)=>{var n;n=e,console.log("updateBaseData"),F("updateBaseData",n).then((e=>{200!=e.status&&H(new Error(`Unable to update base data: ${e.statusText} (${e.status})`))})),$({})},onError:b("errors"),formData:C}),r().createElement("hr",{style:{width:"100%",height:"1px",color:"gray","background-color":"gray","text-align":"left","margin-left":0}}),r().createElement("p",null),r().createElement("p",null),B.deviceCount<B.totalDevices?r().createElement(S.A,{max:B.maxTimeout,now:B.progress}):"",r().createElement("p",null),r().createElement(w.A,{defaultActiveKey:"_configured",id:"domain-tabs",className:"mb-3",onClick:()=>{$({})}},Object.keys(D).map((e=>{return n=(t=e).slice("_"===t.charAt(0)?1:0),r().createElement(y.A,{eventKey:t,title:n.charAt(0).toUpperCase()+n.slice(1)},r().createElement(E.A,{style:{maxHeight:"300px",overflowY:"auto"}},function(e){return D[e]}(t)));var t,n}))),r().createElement("div",{style:{paddingLeft:10,paddingTop:10,display:0==Object.keys(x).length?"none":""}},r().createElement(c.A,{container:!0,direction:"column",style:{spacing:5}},r().createElement(c.A,{item:!0},r().createElement("h2",null,x?.title),r().createElement("p",null)),r().createElement(c.A,{item:!0},(0,l.Ay)(x?.htmlDescription))),r().createElement(a.Ay,{schema:x,validator:o.Ay,uiSchema:T,onChange:e=>{L.get(e.formData.mac_address)._changesMade=!0,U(e.formData)},onSubmit:({formData:e},t)=>{var n;n=e,console.log("updateSensorData"),F("updateSensorData",n).then((e=>{if(200!=e.status)throw new Error(e.statusText);L.get(n.mac_address)._changesMade=!1,L.get(n.mac_address).config=n})),$({}),alert("Changes saved")},onError:b("errors"),formData:O},r().createElement("div",{className:K.root},r().createElement(i.A,{type:"submit",color:"primary",variant:"contained"},"Save"),r().createElement(i.A,{variant:"contained",onClick:()=>{var e;e=O.mac_address,console.log("undoChanges"),L.get(e)._changesMade=!1,U(L.get(e).config)}},"Undo"),r().createElement(i.A,{variant:"contained",color:"secondary",onClick:e=>{return t=O.mac_address,void(window.confirm(`Delete configuration for ${t}?`)&&function(e){console.log("removeSensorData");try{F("removeSensorData",{mac_address:e}).then((e=>{if(200!=e.status)throw new Error(e.statusText)})),A.delete(e),J(new Map(A)),$({})}catch{}}(t));var t}},"Delete")))))}}}]);
package/public/main.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e,r,t={49445:()=>{}},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={exports:{}};return t[e](a,a.exports,o),a.exports}o.m=t,o.c=n,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>e+".js",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="bt-sensors-plugin-sk:",o.l=(t,n,a,i)=>{if(e[t])e[t].push(n);else{var s,l;if(void 0!==a)for(var u=document.getElementsByTagName("script"),c=0;c<u.length;c++){var p=u[c];if(p.getAttribute("src")==t||p.getAttribute("data-webpack")==r+a){s=p;break}}s||(l=!0,(s=document.createElement("script")).charset="utf-8",s.timeout=120,o.nc&&s.setAttribute("nonce",o.nc),s.setAttribute("data-webpack",r+a),s.src=t),e[t]=[n];var d=(r,n)=>{s.onerror=s.onload=null,clearTimeout(f);var o=e[t];if(delete e[t],s.parentNode&&s.parentNode.removeChild(s),o&&o.forEach((e=>e(n))),r)return r(n)},f=setTimeout(d.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=d.bind(null,s.onerror),s.onload=d.bind(null,s.onload),l&&document.head.appendChild(s)}},(()=>{o.S={};var e={},r={};o.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];o.o(o.S,t)||(o.S[t]={});var i=o.S[t],s="bt-sensors-plugin-sk",l=[];return"default"===t&&((e,r,t,n)=>{var a=i[e]=i[e]||{},l=a[r];(!l||!l.loaded&&(1!=!l.eager?n:s>l.from))&&(a[r]={get:()=>o.e(778).then((()=>()=>o(96540))),from:s,eager:!1})})("react","16.14.0"),e[t]=l.length?Promise.all(l).then((()=>e[t]=1)):1}}})(),(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var r=o.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={792:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),s=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;s.message="Loading chunk "+r+" failed.\n("+a+": "+i+")",s.name="ChunkLoadError",s.type=a,s.request=i,n[1](s)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[i,s,l]=t,u=0;if(i.some((r=>0!==e[r]))){for(n in s)o.o(s,n)&&(o.m[n]=s[n]);l&&l(o)}for(r&&r(t);u<i.length;u++)a=i[u],o.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),o(49445)})();
1
+ (()=>{var e,r,t={49445:()=>{}},n={};function o(e){var r=n[e];if(void 0!==r)return r.exports;var a=n[e]={exports:{}};return t[e](a,a.exports,o),a.exports}o.m=t,o.c=n,o.f={},o.e=e=>Promise.all(Object.keys(o.f).reduce(((r,t)=>(o.f[t](e,r),r)),[])),o.u=e=>e+".js",o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="bt-sensors-plugin-sk:",o.l=(t,n,a,i)=>{if(e[t])e[t].push(n);else{var s,l;if(void 0!==a)for(var u=document.getElementsByTagName("script"),c=0;c<u.length;c++){var p=u[c];if(p.getAttribute("src")==t||p.getAttribute("data-webpack")==r+a){s=p;break}}s||(l=!0,(s=document.createElement("script")).charset="utf-8",s.timeout=120,o.nc&&s.setAttribute("nonce",o.nc),s.setAttribute("data-webpack",r+a),s.src=t),e[t]=[n];var d=(r,n)=>{s.onerror=s.onload=null,clearTimeout(f);var o=e[t];if(delete e[t],s.parentNode&&s.parentNode.removeChild(s),o&&o.forEach((e=>e(n))),r)return r(n)},f=setTimeout(d.bind(null,void 0,{type:"timeout",target:s}),12e4);s.onerror=d.bind(null,s.onerror),s.onload=d.bind(null,s.onload),l&&document.head.appendChild(s)}},(()=>{o.S={};var e={},r={};o.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];o.o(o.S,t)||(o.S[t]={});var i=o.S[t],s="bt-sensors-plugin-sk",l=[];return"default"===t&&((e,r,t,n)=>{var a=i[e]=i[e]||{},l=a[r];(!l||!l.loaded&&(1!=!l.eager?n:s>l.from))&&(a[r]={get:()=>o.e(159).then((()=>()=>o(96540))),from:s,eager:!1})})("react","16.14.0"),e[t]=l.length?Promise.all(l).then((()=>e[t]=1)):1}}})(),(()=>{var e;o.g.importScripts&&(e=o.g.location+"");var r=o.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=e})(),(()=>{var e={792:0};o.f.j=(r,t)=>{var n=o.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=a);var i=o.p+o.u(r),s=new Error;o.l(i,(t=>{if(o.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),i=t&&t.target&&t.target.src;s.message="Loading chunk "+r+" failed.\n("+a+": "+i+")",s.name="ChunkLoadError",s.type=a,s.request=i,n[1](s)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[i,s,l]=t,u=0;if(i.some((r=>0!==e[r]))){for(n in s)o.o(s,n)&&(o.m[n]=s[n]);l&&l(o)}for(r&&r(t);u<i.length;u++)a=i[u],o.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),o(49445)})();
@@ -1 +1 @@
1
- var bt_sensors_plugin_sk;(()=>{"use strict";var e,r,t,n,a,o,i,u,s,l,f,d,c,p,h,v,g,b,m,y,w,k={43237:(e,r,t)=>{var n={"./PluginConfigurationPanel":()=>Promise.all([t.e(239),t.e(159)]).then((()=>()=>t(62995)))},a=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then((()=>{throw new Error('Module "'+e+'" does not exist in container.')})),t.R=void 0,r),o=(e,r)=>{if(t.S){var n="default",a=t.S[n];if(a&&a!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>a,init:()=>o})}},S={};function _(e){var r=S[e];if(void 0!==r)return r.exports;var t=S[e]={id:e,loaded:!1,exports:{}};return k[e](t,t.exports,_),t.loaded=!0,t.exports}_.m=k,_.c=S,_.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return _.d(r,{a:r}),r},_.d=(e,r)=>{for(var t in r)_.o(r,t)&&!_.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},_.f={},_.e=e=>Promise.all(Object.keys(_.f).reduce(((r,t)=>(_.f[t](e,r),r)),[])),_.u=e=>e+".js",_.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),_.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="bt-sensors-plugin-sk:",_.l=(t,n,a,o)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==a)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var f=s[l];if(f.getAttribute("src")==t||f.getAttribute("data-webpack")==r+a){i=f;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,_.nc&&i.setAttribute("nonce",_.nc),i.setAttribute("data-webpack",r+a),i.src=t),e[t]=[n];var d=(r,n)=>{i.onerror=i.onload=null,clearTimeout(c);var a=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),a&&a.forEach((e=>e(n))),r)return r(n)},c=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),u&&document.head.appendChild(i)}},_.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},_.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{_.S={};var e={},r={};_.I=(t,n)=>{n||(n=[]);var a=r[t];if(a||(a=r[t]={}),!(n.indexOf(a)>=0)){if(n.push(a),e[t])return e[t];_.o(_.S,t)||(_.S[t]={});var o=_.S[t],i="bt-sensors-plugin-sk",u=[];return"default"===t&&((e,r,t,n)=>{var a=o[e]=o[e]||{},u=a[r];(!u||!u.loaded&&(1!=!u.eager?n:i>u.from))&&(a[r]={get:()=>_.e(778).then((()=>()=>_(96540))),from:i,eager:!1})})("react","16.14.0"),e[t]=u.length?Promise.all(u).then((()=>e[t]=1)):1}}})(),(()=>{var e;_.g.importScripts&&(e=_.g.location+"");var r=_.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),_.p=e})(),t=e=>{var r=e=>e.split(".").map((e=>+e==e?+e:e)),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var a=e[n],o=(typeof a)[0];if(n>=r.length)return"u"==o;var i=r[n],u=(typeof i)[0];if(o!=u)return"o"==o&&"n"==u||"s"==u||"u"==o;if("o"!=o&&"u"!=o&&a!=i)return a<i;n++}},a=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,o=1;o<e.length;o++)n--,t+="u"==(typeof(u=e[o]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(o=1;o<e.length;o++){var u=e[o];i.push(0===u?"not("+s()+")":1===u?"("+s()+" || "+s()+")":2===u?i.pop()+" "+i.pop():a(u))}return s();function s(){return i.pop().replace(/^\((.+)\)$/,"$1")}},o=(e,r)=>{if(0 in e){r=t(r);var n=e[0],a=n<0;a&&(n=-n-1);for(var i=0,u=1,s=!0;;u++,i++){var l,f,d=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(f=(typeof(l=r[i]))[0]))return!s||("u"==d?u>n&&!a:""==d!=a);if("u"==f){if(!s||"u"!=d)return!1}else if(s)if(d==f)if(u<=n){if(l!=e[u])return!1}else{if(a?l>e[u]:l<e[u])return!1;l!=e[u]&&(s=!1)}else if("s"!=d&&"n"!=d){if(a||u<=n)return!1;s=!1,u--}else{if(u<=n||f<d!=a)return!1;s=!1}else"s"!=d&&"n"!=d&&(s=!1,u--)}}var c=[],p=c.pop.bind(c);for(i=1;i<e.length;i++){var h=e[i];c.push(1==h?p()|p():2==h?p()&p():h?o(h,r):!p())}return!!p()},i=(e,r)=>e&&_.o(e,r),u=e=>(e.loaded=1,e.get()),s=e=>Object.keys(e).reduce(((r,t)=>(e[t].eager&&(r[t]=e[t]),r)),{}),l=(e,r,t)=>{var a=t?s(e[r]):e[r];return(r=Object.keys(a).reduce(((e,r)=>!e||n(e,r)?r:e),0))&&a[r]},f=(e,r,t,a)=>{var i=a?s(e[r]):e[r];return(r=Object.keys(i).reduce(((e,r)=>!o(t,r)||e&&!n(e,r)?e:r),0))&&i[r]},d=(e,r,t,n,o)=>{var i=e[t];return"No satisfying version ("+a(n)+")"+(o?" for eager consumption":"")+" of shared module "+t+" found in shared scope "+r+".\nAvailable versions: "+Object.keys(i).map((e=>e+" from "+i[e].from)).join(", ")},c=e=>{throw new Error(e)},h=(e,r,t)=>t?t():((e,r)=>c("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(p=e=>function(r,t,n,a,o){var i=_.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,_.S[r],t,!1,a,o)):e(r,_.S[r],t,n,a,o)})(((e,r,t,n,a)=>i(r,t)?u(l(r,t,n)):h(e,t,a))),g=p(((e,r,t,n,a,o)=>{if(!i(r,t))return h(e,t,o);var s=f(r,t,a,n);return s?u(s):o?o():void c(d(r,e,t,a,n))})),b={},m={21490:()=>g("default","react",!1,[,[1,17,0,0],[1,16,8,0],1],(()=>_.e(540).then((()=>()=>_(96540))))),42417:()=>g("default","react",!1,[0,16,8,0],(()=>_.e(540).then((()=>()=>_(96540))))),44167:()=>v("default","react",!1,(()=>_.e(540).then((()=>()=>_(96540))))),57920:()=>g("default","react",!1,[,[0,17],[1,16,14,0],1],(()=>_.e(540).then((()=>()=>_(96540))))),62085:()=>g("default","react",!1,[1,16,14,0],(()=>_.e(540).then((()=>()=>_(96540))))),64115:()=>g("default","react",!1,[,[1,19,0,0,,"rc",1],[1,18,0,0],[1,17,0,0,,"rc",1],[1,16,8,0],1,1,1],(()=>_.e(540).then((()=>()=>_(96540))))),64564:()=>g("default","react",!1,[0,16,14,0],(()=>_.e(540).then((()=>()=>_(96540))))),86528:()=>g("default","react",!1,[1,16,13,1],(()=>_.e(540).then((()=>()=>_(96540))))),87227:()=>g("default","react",!1,[0,16,6,0],(()=>_.e(540).then((()=>()=>_(96540))))),96932:()=>g("default","react",!1,[0,15,0,0],(()=>_.e(540).then((()=>()=>_(96540))))),98271:()=>g("default","react",!1,[0,0,14,0],(()=>_.e(540).then((()=>()=>_(96540)))))},y={159:[21490,42417,44167,57920,62085,64115,64564,86528,87227,96932,98271]},w={},_.f.consumes=(e,r)=>{_.o(y,e)&&y[e].forEach((e=>{if(_.o(b,e))return r.push(b[e]);if(!w[e]){var t=r=>{b[e]=0,_.m[e]=t=>{delete _.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete b[e],_.m[e]=t=>{throw delete _.c[e],r}};try{var a=m[e]();a.then?r.push(b[e]=a.then(t).catch(n)):t(a)}catch(e){n(e)}}}))},(()=>{var e={592:0};_.f.j=(r,t)=>{var n=_.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var a=new Promise(((t,a)=>n=e[r]=[t,a]));t.push(n[2]=a);var o=_.p+_.u(r),i=new Error;_.l(o,(t=>{if(_.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var a=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+a+": "+o+")",i.name="ChunkLoadError",i.type=a,i.request=o,n[1](i)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,a,[o,i,u]=t,s=0;if(o.some((r=>0!==e[r]))){for(n in i)_.o(i,n)&&(_.m[n]=i[n]);u&&u(_)}for(r&&r(t);s<o.length;s++)a=o[s],_.o(e,a)&&e[a]&&e[a][0](),e[a]=0},t=self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var j=_(43237);bt_sensors_plugin_sk=j})();
1
+ var bt_sensors_plugin_sk;(()=>{"use strict";var e,r,t,n,o,a,i,u,s,l,f,d,c,p,h,v,g,b,m,y,w,k={43237:(e,r,t)=>{var n={"./PluginConfigurationPanel":()=>Promise.all([t.e(681),t.e(847)]).then((()=>()=>t(62995)))},o=(e,r)=>(t.R=r,r=t.o(n,e)?n[e]():Promise.resolve().then((()=>{throw new Error('Module "'+e+'" does not exist in container.')})),t.R=void 0,r),a=(e,r)=>{if(t.S){var n="default",o=t.S[n];if(o&&o!==e)throw new Error("Container initialization failed as it has already been initialized with a different share scope");return t.S[n]=e,t.I(n,r)}};t.d(r,{get:()=>o,init:()=>a})}},S={};function _(e){var r=S[e];if(void 0!==r)return r.exports;var t=S[e]={id:e,loaded:!1,exports:{}};return k[e].call(t.exports,t,t.exports,_),t.loaded=!0,t.exports}_.m=k,_.c=S,_.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return _.d(r,{a:r}),r},_.d=(e,r)=>{for(var t in r)_.o(r,t)&&!_.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},_.f={},_.e=e=>Promise.all(Object.keys(_.f).reduce(((r,t)=>(_.f[t](e,r),r)),[])),_.u=e=>e+".js",_.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),_.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),e={},r="bt-sensors-plugin-sk:",_.l=(t,n,o,a)=>{if(e[t])e[t].push(n);else{var i,u;if(void 0!==o)for(var s=document.getElementsByTagName("script"),l=0;l<s.length;l++){var f=s[l];if(f.getAttribute("src")==t||f.getAttribute("data-webpack")==r+o){i=f;break}}i||(u=!0,(i=document.createElement("script")).charset="utf-8",i.timeout=120,_.nc&&i.setAttribute("nonce",_.nc),i.setAttribute("data-webpack",r+o),i.src=t),e[t]=[n];var d=(r,n)=>{i.onerror=i.onload=null,clearTimeout(c);var o=e[t];if(delete e[t],i.parentNode&&i.parentNode.removeChild(i),o&&o.forEach((e=>e(n))),r)return r(n)},c=setTimeout(d.bind(null,void 0,{type:"timeout",target:i}),12e4);i.onerror=d.bind(null,i.onerror),i.onload=d.bind(null,i.onload),u&&document.head.appendChild(i)}},_.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},_.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{_.S={};var e={},r={};_.I=(t,n)=>{n||(n=[]);var o=r[t];if(o||(o=r[t]={}),!(n.indexOf(o)>=0)){if(n.push(o),e[t])return e[t];_.o(_.S,t)||(_.S[t]={});var a=_.S[t],i="bt-sensors-plugin-sk",u=[];return"default"===t&&((e,r,t,n)=>{var o=a[e]=a[e]||{},u=o[r];(!u||!u.loaded&&(1!=!u.eager?n:i>u.from))&&(o[r]={get:()=>_.e(159).then((()=>()=>_(96540))),from:i,eager:!1})})("react","16.14.0"),e[t]=u.length?Promise.all(u).then((()=>e[t]=1)):1}}})(),(()=>{var e;_.g.importScripts&&(e=_.g.location+"");var r=_.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var n=t.length-1;n>-1&&(!e||!/^http(s?):/.test(e));)e=t[n--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),_.p=e})(),t=e=>{var r=e=>e.split(".").map((e=>+e==e?+e:e)),t=/^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(e),n=t[1]?r(t[1]):[];return t[2]&&(n.length++,n.push.apply(n,r(t[2]))),t[3]&&(n.push([]),n.push.apply(n,r(t[3]))),n},n=(e,r)=>{e=t(e),r=t(r);for(var n=0;;){if(n>=e.length)return n<r.length&&"u"!=(typeof r[n])[0];var o=e[n],a=(typeof o)[0];if(n>=r.length)return"u"==a;var i=r[n],u=(typeof i)[0];if(a!=u)return"o"==a&&"n"==u||"s"==u||"u"==a;if("o"!=a&&"u"!=a&&o!=i)return o<i;n++}},o=e=>{var r=e[0],t="";if(1===e.length)return"*";if(r+.5){t+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var n=1,a=1;a<e.length;a++)n--,t+="u"==(typeof(u=e[a]))[0]?"-":(n>0?".":"")+(n=2,u);return t}var i=[];for(a=1;a<e.length;a++){var u=e[a];i.push(0===u?"not("+s()+")":1===u?"("+s()+" || "+s()+")":2===u?i.pop()+" "+i.pop():o(u))}return s();function s(){return i.pop().replace(/^\((.+)\)$/,"$1")}},a=(e,r)=>{if(0 in e){r=t(r);var n=e[0],o=n<0;o&&(n=-n-1);for(var i=0,u=1,s=!0;;u++,i++){var l,f,d=u<e.length?(typeof e[u])[0]:"";if(i>=r.length||"o"==(f=(typeof(l=r[i]))[0]))return!s||("u"==d?u>n&&!o:""==d!=o);if("u"==f){if(!s||"u"!=d)return!1}else if(s)if(d==f)if(u<=n){if(l!=e[u])return!1}else{if(o?l>e[u]:l<e[u])return!1;l!=e[u]&&(s=!1)}else if("s"!=d&&"n"!=d){if(o||u<=n)return!1;s=!1,u--}else{if(u<=n||f<d!=o)return!1;s=!1}else"s"!=d&&"n"!=d&&(s=!1,u--)}}var c=[],p=c.pop.bind(c);for(i=1;i<e.length;i++){var h=e[i];c.push(1==h?p()|p():2==h?p()&p():h?a(h,r):!p())}return!!p()},i=(e,r)=>e&&_.o(e,r),u=e=>(e.loaded=1,e.get()),s=e=>Object.keys(e).reduce(((r,t)=>(e[t].eager&&(r[t]=e[t]),r)),{}),l=(e,r,t)=>{var o=t?s(e[r]):e[r];return(r=Object.keys(o).reduce(((e,r)=>!e||n(e,r)?r:e),0))&&o[r]},f=(e,r,t,o)=>{var i=o?s(e[r]):e[r];return(r=Object.keys(i).reduce(((e,r)=>!a(t,r)||e&&!n(e,r)?e:r),0))&&i[r]},d=(e,r,t,n,a)=>{var i=e[t];return"No satisfying version ("+o(n)+")"+(a?" for eager consumption":"")+" of shared module "+t+" found in shared scope "+r+".\nAvailable versions: "+Object.keys(i).map((e=>e+" from "+i[e].from)).join(", ")},c=e=>{throw new Error(e)},h=(e,r,t)=>t?t():((e,r)=>c("Shared module "+r+" doesn't exist in shared scope "+e))(e,r),v=(p=e=>function(r,t,n,o,a){var i=_.I(r);return i&&i.then&&!n?i.then(e.bind(e,r,_.S[r],t,!1,o,a)):e(r,_.S[r],t,n,o,a)})(((e,r,t,n,o)=>i(r,t)?u(l(r,t,n)):h(e,t,o))),g=p(((e,r,t,n,o,a)=>{if(!i(r,t))return h(e,t,a);var s=f(r,t,o,n);return s?u(s):a?a():void c(d(r,e,t,o,n))})),b={},m={21490:()=>g("default","react",!1,[,[1,17,0,0],[1,16,8,0],1],(()=>_.e(540).then((()=>()=>_(96540))))),42417:()=>g("default","react",!1,[0,16,8,0],(()=>_.e(540).then((()=>()=>_(96540))))),44167:()=>v("default","react",!1,(()=>_.e(540).then((()=>()=>_(96540))))),57920:()=>g("default","react",!1,[,[0,17],[1,16,14,0],1],(()=>_.e(540).then((()=>()=>_(96540))))),61104:()=>g("default","react",!1,[,[1,16,0,0,,0],[1,15,0,0],[2,0,14,0],1,1],(()=>_.e(540).then((()=>()=>_(96540))))),62085:()=>g("default","react",!1,[1,16,14,0],(()=>_.e(540).then((()=>()=>_(96540))))),86528:()=>g("default","react",!1,[1,16,13,1],(()=>_.e(540).then((()=>()=>_(96540))))),87227:()=>g("default","react",!1,[0,16,6,0],(()=>_.e(540).then((()=>()=>_(96540))))),96932:()=>g("default","react",!1,[0,15,0,0],(()=>_.e(540).then((()=>()=>_(96540))))),98271:()=>g("default","react",!1,[0,0,14,0],(()=>_.e(540).then((()=>()=>_(96540)))))},y={847:[21490,42417,44167,57920,61104,62085,86528,87227,96932,98271]},w={},_.f.consumes=(e,r)=>{_.o(y,e)&&y[e].forEach((e=>{if(_.o(b,e))return r.push(b[e]);if(!w[e]){var t=r=>{b[e]=0,_.m[e]=t=>{delete _.c[e],t.exports=r()}};w[e]=!0;var n=r=>{delete b[e],_.m[e]=t=>{throw delete _.c[e],r}};try{var o=m[e]();o.then?r.push(b[e]=o.then(t).catch(n)):t(o)}catch(e){n(e)}}}))},(()=>{var e={592:0};_.f.j=(r,t)=>{var n=_.o(e,r)?e[r]:void 0;if(0!==n)if(n)t.push(n[2]);else{var o=new Promise(((t,o)=>n=e[r]=[t,o]));t.push(n[2]=o);var a=_.p+_.u(r),i=new Error;_.l(a,(t=>{if(_.o(e,r)&&(0!==(n=e[r])&&(e[r]=void 0),n)){var o=t&&("load"===t.type?"missing":t.type),a=t&&t.target&&t.target.src;i.message="Loading chunk "+r+" failed.\n("+o+": "+a+")",i.name="ChunkLoadError",i.type=o,i.request=a,n[1](i)}}),"chunk-"+r,r)}};var r=(r,t)=>{var n,o,[a,i,u]=t,s=0;if(a.some((r=>0!==e[r]))){for(n in i)_.o(i,n)&&(_.m[n]=i[n]);u&&u(_)}for(r&&r(t);s<a.length;s++)o=a[s],_.o(e,o)&&e[o]&&e[o][0](),e[o]=0},t=self.webpackChunkbt_sensors_plugin_sk=self.webpackChunkbt_sensors_plugin_sk||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})();var j=_(43237);bt_sensors_plugin_sk=j})();
@@ -24,7 +24,7 @@ class ATC extends BTSensor{
24
24
  {
25
25
  title:'data parsing strategy',
26
26
  type: 'string',
27
- enum:["ATC-LE","ATC-BE"],
27
+ enum:["ATC-LE","ATC-BE", "ATC-Exploit"],
28
28
  default: "ATC-LE"
29
29
  }
30
30
  )
@@ -51,6 +51,20 @@ class ATC extends BTSensor{
51
51
 
52
52
  } else{
53
53
 
54
+ if (this.parser=="ATC-Exploit"){
55
+ this.getPath("batteryStrength")
56
+ .read=(buff)=>{return ((buff.readUInt8(9))/100)}
57
+
58
+ this.addDefaultPath('voltage','sensors.batteryVoltage')
59
+ .read=(buff)=>{return ((buff.readUInt16BE(10))/1000)}
60
+
61
+ this.addDefaultPath('temp', 'environment.temperature')
62
+ .read=(buff)=>{return parseFloat((273.15+(buff.readInt16BE(6))/10).toFixed(2))}
63
+
64
+ this.addDefaultPath('humidity','environment.humidity')
65
+ .read=(buff)=>{return ((buff.readUInt8(8))/100)}
66
+ }
67
+ else{
54
68
  this.addDefaultPath('voltage','sensors.batteryVoltage')
55
69
  .read=(buff)=>{return ((buff.readUInt16BE(10))/1000)}
56
70
 
@@ -59,6 +73,7 @@ class ATC extends BTSensor{
59
73
 
60
74
  this.addDefaultPath('humidity','environment.humidity')
61
75
  .read=(buff)=>{return ((buff.readUInt16BE(8))/10000)}
76
+ }
62
77
 
63
78
  }
64
79
  }
@@ -81,5 +96,11 @@ class ATC extends BTSensor{
81
96
  getManufacturer(){
82
97
  return "ATC1441 (custom firmware see: https://github.com/atc1441)"
83
98
  }
99
+
100
+ getDescription(){
101
+ return `<div><p><img src="../bt-sensors-plugin-sk/images/LYWSD03MMC-Device.jpg" alt="ATC/LYWSD03MMC image" style="float: left; margin-right: 10px;" />
102
+ Xiaomi LYWSD03MMC custom firmware provided by <b>ATC1441</b>.
103
+ For more information, see: <a href=https://github.com/atc1441/ATC_MiThermometer?tab=readme-ov-file#atc_mithermometer target="_blank">ATC_MiThermometer</a><div>`
104
+ }
84
105
  }
85
106
  module.exports=ATC
@@ -3,10 +3,18 @@ class BLACKLISTED extends BTSensor {
3
3
  static isSystem = true;
4
4
  static async identify(device) {
5
5
  const md = await this.getDeviceProp(device, "ManufacturerData");
6
+ const addrType = await this.getDeviceProp(device, "AddressType");
7
+ const addr = await this.getDeviceProp(device, "Address")
8
+ const addrFirstByte = addr?parseInt((addr)[0]):0
9
+ if (addrType=="random" && addrFirstByte >= 4 && addrFirstByte<=7) {
10
+ return this
11
+ }
12
+
6
13
  if (md && Object.hasOwn(md, 0x004c)){
7
14
  if (md[0x004c].value.slice(0,2).join() != [0x02, 0x15].join()){ // iBeacons are exempt
8
15
  return this;
9
16
  }
17
+
10
18
  return null;
11
19
  }
12
20
  }
@@ -23,14 +31,9 @@ class BLACKLISTED extends BTSensor {
23
31
  switch (this.getManufacturerID()) {
24
32
  case 0x004c:
25
33
  return "Randomized MAC address (Apple)";
26
- case 0x02e1:
27
- return "Device is using VE.Smart"; //NOTE: Victron/VictronSensor class
28
- //determines if a device is using VE.Smart
29
- //in identify(). If so, identify() returns
30
- //BlackListedDevice
31
-
34
+
32
35
  default:
33
- return "";
36
+ return "Random Private Address";
34
37
  }
35
38
  }
36
39
  }
@@ -338,8 +338,23 @@ class GobiusCTankMeter extends BTSensor{
338
338
  this.service = await this.gattServer.getPrimaryService("0000ffe0-0000-1000-8000-00805f9b34fb")
339
339
  this.characteristic = await this.service.getCharacteristic("0000ffe9-0000-1000-8000-00805f9b34fb")
340
340
  }
341
+ this.device.on("disconnect", ()=>{
342
+ if (this.isActive()) {
343
+ this.debug(`Device disconnected. Attempting to reconnect to ${this.getName()}`)
344
+ try {
345
+ this.deviceConnect().then(()=>{
346
+ this.debug(`Device reconnected -- ${this.getName()}`)
347
+ })
348
+ }
349
+ catch (e) {
350
+ this.debug(`Error while reconnecting to ${this.getName()}`)
351
+ }
352
+ }
353
+ })
354
+
341
355
  resolve(this)
342
356
  }).catch((e)=>{ reject(e.message) }) })
357
+
343
358
  }
344
359
  initGATTNotifications() {
345
360
  Promise.resolve(this.characteristic.startNotifications().then(()=>{
@@ -348,7 +363,9 @@ class GobiusCTankMeter extends BTSensor{
348
363
  })
349
364
  }))
350
365
  }
351
-
366
+ getDescription(){
367
+ return '<a href="https://gobiusc.com/"><img src="../bt-sensors-plugin-sk/images/Gobius_C.png" alt="Gobius C Tank Measure" "></a>'
368
+ }
352
369
  async stopListening(){
353
370
  super.stopListening()
354
371
  if (this.characteristic && await this.characteristic.isNotifying()) {
@@ -1,9 +1,24 @@
1
1
  const BTSensor = require("../BTSensor");
2
- function sleep(ms) {
3
- return new Promise((resolve) => {
4
- setTimeout(resolve, ms);
5
- });
2
+ function sumByteArray(byteArray) {
3
+ let sum = 0;
4
+ for (let i = 0; i < byteArray.length; i++) {
5
+ sum += byteArray[i];
6
+ }
7
+ return sum;
8
+ }
9
+
10
+ function checkSum(buffer){
11
+ if (buffer.length<5) {
12
+ console.log (`Can't checksum ${buffer}. Invalid buffer. Buffer must be at least 5 bytes long.`)
13
+ return false
14
+ }
15
+ const checksum = buffer.readUInt16BE(buffer.length-3)
16
+ let sum = sumByteArray(Uint8Array.prototype.slice.call(buffer, 2, buffer.length-3))
17
+ if ((0xffff-sum)+1 == checksum) return true
18
+ sum = sumByteArray(Uint8Array.prototype.slice.call(buffer, 2, buffer.length-2))
19
+ return (0xffff-sum)+1 == checksum
6
20
  }
21
+
7
22
  class JBDBMS extends BTSensor {
8
23
  static Domain = BTSensor.SensorDomains.electrical
9
24
 
@@ -11,24 +26,18 @@ class JBDBMS extends BTSensor {
11
26
  static NOTIFY_CHAR_UUID = "0000ff01-0000-1000-8000-00805f9b34fb"
12
27
  static WRITE_CHAR_UUID = "0000ff02-0000-1000-8000-00805f9b34fb"
13
28
 
14
- constructor(device,config,gattConfig){
15
- super(device,config,gattConfig)
16
- this.emitterFunctions=
17
- [this.getAndEmitBatteryInfo.bind(this),
18
- this.getAndEmitCellVoltages.bind(this)]
19
-
20
- }
21
29
  static identify(device){
22
30
  return null
23
31
  }
32
+
24
33
  jbdCommand(command) {
25
34
  return [0xDD, 0xA5, command, 0x00, 0xFF, 0xFF - (command - 1), 0x77]
26
35
  }
27
36
 
28
37
  async sendReadFunctionRequest( command ){
29
- return await this.txChar.writeValueWithResponse(Buffer.from(this.jbdCommand(command)))
30
-
31
- }
38
+ this.debug( `sending ${command}`)
39
+ return await this.txChar.writeValueWithoutResponse(Buffer.from(this.jbdCommand(command)))
40
+ }
32
41
 
33
42
  async initSchema(){
34
43
  super.initSchema()
@@ -62,11 +71,16 @@ class JBDBMS extends BTSensor {
62
71
  (buffer)=>{return buffer.readUInt8(24)} )
63
72
  .default="electrical.batteries.{batteryID}.FETControl"
64
73
 
65
- await this.deviceConnect()
66
- await this.initCharacteristics()
67
- const cellsAndTemps = await this.getNumberOfCellsAndTemps()
68
- this.numberOfCells=cellsAndTemps.cells
69
- this.numberOfTemps=cellsAndTemps.temps
74
+ await this.deviceConnect()
75
+ const gattServer = await this.device.gatt()
76
+ const txRxService= await gattServer.getPrimaryService(this.constructor.TX_RX_SERVICE)
77
+ this.rxChar = await txRxService.getCharacteristic(this.constructor.NOTIFY_CHAR_UUID)
78
+ this.txChar = await txRxService.getCharacteristic(this.constructor.WRITE_CHAR_UUID)
79
+ await this.rxChar.startNotifications()
80
+
81
+ const cellsAndTemps = await this.getNumberOfCellsAndTemps()
82
+ this.numberOfCells=cellsAndTemps.cells
83
+ this.numberOfTemps=cellsAndTemps.temps
70
84
 
71
85
  for (let i=0; i<this.numberOfTemps; i++){
72
86
  this.addMetadatum(`temp${i}`, 'K', `Temperature${i+1} reading`,
@@ -80,66 +94,75 @@ class JBDBMS extends BTSensor {
80
94
  this.addMetadatum(`cell${i}Voltage`, 'V', `Cell ${i+1} voltage`,
81
95
  (buffer)=>{return buffer.readUInt16BE((4+(i*2)))/1000} )
82
96
  .default=`electrical.batteries.{batteryID}.cell${i}.voltage`
83
- this.addMetadatum(`cell${i}Balance`, 'V', `Cell ${i+1} balance` )
97
+ this.addMetadatum(`cell${i}Balance`, '', `Cell ${i+1} balance` )
84
98
  .default=`electrical.batteries.{batteryID}.cell${i}.balance`
85
99
 
86
100
  }
87
101
  }
102
+
88
103
  hasGATT(){
89
104
  return true
90
105
  }
91
- async initCharacteristics(){
92
- const gattServer = await this.device.gatt()
93
- const txRxService= await gattServer.getPrimaryService(this.constructor.TX_RX_SERVICE)
94
- this.rxChar = await txRxService.getCharacteristic(this.constructor.NOTIFY_CHAR_UUID)
95
- this.txChar = await txRxService.getCharacteristic(this.constructor.WRITE_CHAR_UUID)
96
- await this.rxChar.startNotifications()
97
- return this
98
- }
99
-
100
- async initGATTNotifications(){
101
- this.intervalID = setInterval(()=>{
102
-
103
- this.emitGATT()
106
+ initGATTNotifications(){
107
+ this.intervalID = setInterval( async ()=>{
108
+ await this.emitGATT()
104
109
  }, 1000*(this?.pollFreq??60) )
105
110
  }
106
111
 
107
- emitGATT(){
108
- this.getAndEmitBatteryInfo()
109
- setTimeout(()=>{this.getAndEmitCellVoltages()}, 10000)
110
- }
111
-
112
+ async emitGATT(){
113
+ try {
114
+ await this.getAndEmitBatteryInfo()
115
+ }
116
+ catch (e) {
117
+ this.debug(`Failed to emit battery info for ${this.getName()}: ${e}`)
118
+ }
119
+ setTimeout(async ()=>{
120
+ try {await this.getAndEmitCellVoltages()}
121
+ catch (e) {
122
+ this.debug(`Failed to emit Cell Voltages for ${this.getName()}: ${e}`)
123
+ }
124
+ }, 10000)
125
+ }
112
126
 
113
127
  async getNumberOfCellsAndTemps(){
114
- var b = await this.getBuffer(0x3)
128
+ const b = await this.getBuffer(0x3)
115
129
  return {cells:b[25], temps:b[26]}
116
130
  }
117
131
 
118
132
 
119
- getBuffer(command){
133
+ getBuffer (command){
120
134
 
121
135
  return new Promise( async ( resolve, reject )=>{
122
136
  const r = await this.sendReadFunctionRequest(command)
123
- const result = Buffer.alloc(256)
124
- var offset = 0
125
-
137
+ let result = Buffer.alloc(256)
138
+ let offset = 0
139
+ let datasize = -1
126
140
  const timer = setTimeout(() => {
127
141
  clearTimeout(timer)
128
142
  reject(new Error(`Response timed out from JBDBMS device ${this.getName()}. `));
129
143
  }, 30000);
130
144
 
131
145
  const valChanged = async (buffer) => {
146
+ if (offset==0){ //first packet
147
+ if (buffer[0]!==0xDD || buffer.length < 5 || buffer[1] !== command)
148
+ reject(`Invalid buffer from ${this.getName()}, not processing.`)
149
+ else
150
+ datasize=buffer[2]
151
+ }
132
152
  buffer.copy(result,offset)
133
- if (buffer[buffer.length-1]==0x77){
153
+ if (buffer[buffer.length-1]==0x77 && offset+buffer.length-6==datasize){
154
+
155
+ result = Uint8Array.prototype.slice.call(result, 0, offset+buffer.length)
134
156
  this.debug(result)
135
157
  this.rxChar.removeAllListeners()
136
158
  clearTimeout(timer)
159
+ if (!checkSum(result))
160
+ reject(`Invalid checksum from ${this.getName()}, not processing.`)
161
+
137
162
  resolve(result)
138
163
  }
139
164
  offset+=buffer.length
140
165
  }
141
-
142
-
143
166
  this.rxChar.on('valuechanged', valChanged )
144
167
  })
145
168
  }
@@ -148,8 +171,8 @@ async initGATTConnection() {
148
171
  return this
149
172
  }
150
173
 
151
- getAndEmitBatteryInfo(){
152
- this.getBuffer(0x03).then((buffer)=>{
174
+ async getAndEmitBatteryInfo(){
175
+ return this.getBuffer(0x03).then((buffer)=>{
153
176
  (["current", "voltage", "remainingCapacity", "capacity","cycles", "protectionStatus", "SOC","FET",]).forEach((tag) =>
154
177
  this.emitData( tag, buffer )
155
178
  )
@@ -164,9 +187,10 @@ getAndEmitBatteryInfo(){
164
187
  })
165
188
  }
166
189
 
167
- getAndEmitCellVoltages(){
168
- this.getBuffer(0x4).then((buffer)=>{
169
- for (let i=0; i<this.numberOfCells; i++){
190
+ async getAndEmitCellVoltages(){
191
+ return this.getBuffer(0x4).then((buffer)=>{
192
+
193
+ for (let i=0; i<this.numberOfCells; i++){
170
194
  this.emitData(`cell${i}Voltage`,buffer)
171
195
  }})
172
196
  }
@@ -4,7 +4,6 @@
4
4
 
5
5
  const RenogySensor = require("./Renogy/RenogySensor.js");
6
6
  const RC=require("./Renogy/RenogyConstants.js")
7
- const crc16Modbus = require('./Renogy/CRC.js')
8
7
 
9
8
  class RenogyRoverClient extends RenogySensor {
10
9
 
@@ -21,6 +21,10 @@ class ShellySBMO003Z extends AbstractBTHomeSensor {
21
21
  */
22
22
  static LOCAL_NAME="Shelly BLU Motion";
23
23
 
24
+ getDescription(){
25
+ return `NOTE: Device must be paired with SignalK server machine to operate properly. For more information about the sensor go here: <a href=https://us.shelly.com/products/shelly-blu-motion target="_blank">Shelly Blu Motion</a>.`
26
+ }
27
+
24
28
  initSchema() {
25
29
  super.initSchema()
26
30
  this.addDefaultParam("zone")
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Class to support Batteries with embedded Shenzhen Li-ion Battery Bodyguard Technology BMS
3
+ * Brands include Redodo, Litime PowerQueen and possibly others
4
+ */
5
+
6
+
7
+ const BTSensor = require("../BTSensor");
8
+
9
+ const ProtectionStatus = {
10
+ 0x4:"Over Charge Protection",
11
+ 0x20:"Over-discharge Protection",
12
+ 0x40: "Charging Over Current Protection",
13
+ 0x80: "Discharging Over Current Protection",
14
+ 0x100: "High-temp Protection" ,
15
+ 0x200: "High-temp Protection",
16
+ 0x400: "Low-temp Protection",
17
+ 0x800: "Low-temp Protection",
18
+ 0x4000: "Short Circuit Protection"
19
+ }
20
+
21
+ class ShenzhenLiONBMS extends BTSensor{
22
+ static Domain = BTSensor.SensorDomains.electrical
23
+ static Commands = {
24
+ product_registration: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x01, 0x55, 0xAA, 0x05]),
25
+ disconnect_registration: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x02, 0x55, 0xAA, 0x06]),
26
+ query_battery_status: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x13, 0x55, 0xAA, 0x17]),
27
+ turn_on_charging: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x0a, 0x55, 0xAA, 0x0e]),
28
+ turn_off_charging: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x0b, 0x55, 0xAA, 0x0f]),
29
+ turn_on_discharge: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x0c, 0x55, 0xAA, 0x0e]),
30
+ turn_off_discharge: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x0d, 0x55, 0xAA, 0x0f]),
31
+ get_version: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x16, 0x55, 0xAA, 0x1a]),
32
+ get_serial_number: new Uint8Array([0x00, 0x00, 0x04, 0x01, 0x10, 0x55, 0xAA, 0x14])
33
+ };
34
+ static async identify(device){
35
+ return null
36
+ }
37
+ hasGATT(){
38
+ return true
39
+ }
40
+ usingGATT(){
41
+ return true
42
+ }
43
+ emitGATT(){
44
+ this.characteristic.readValue()
45
+ .then((buffer)=>
46
+ this.emitValuesFrom( buffer)
47
+ )
48
+
49
+ }
50
+ initSchema(){
51
+ super.initSchema()
52
+ this.getGATTParams()["useGATT"].default=true
53
+
54
+ this.addDefaultParam("batteryID").default="house"
55
+
56
+ this.addParameter(
57
+ "numberOfCells",
58
+ {
59
+ title:"Number of cells",
60
+ type: "integer",
61
+ default: 4,
62
+ minimum: 1,
63
+ maximum: 16
64
+ }
65
+ )
66
+
67
+ /*
68
+ 'protection_state': t.slice(76, 80).reverse().join(""),//Non all zeros means the BMS is "protecting" the battery somehow. (00000004 = Over Charge Protection, 00000020 = Over-discharge Protection, 00000040 = Charging Over Current Protection, 00000080 = Discharging Over Current Protection, 00000100 = High-temp Protection, 00000200 = High-temp Protection, 00000400 = Low-temp Protection, 00000800 = Low-temp Protection, 00004000 = Short Circuit Protection)
69
+ 'heat': t.slice(68, 72).reverse().join(""),//discharge disabled due to app button = 00000080, heater_error = 00000002
70
+ 'balance_memory_active': t.slice(72, 76).reverse().join(""),//activates when the battery has saved information about what cell it will balance
71
+ 'failure_state': t.slice(80, 84).reverse().join("").slice(-3),//First numer/byte of the three regards cell_error, second number is also cell_error, third number is BMS_error
72
+ 'is_balancing': HexTo2Str(t.slice(84, 88).reverse().join("")),//each bit represents a cell, if the bit = 1 that cell is balancing
73
+ 'battery_state': t.slice(88, 90).reverse().join(""),//charge disabled = "0004", charging = "0001" (when charging active app will show estimated time untill fully charged), discharging/idle: "0000", unkown = "0002"
74
+ 'discharges_count': HexTo10Str(t.slice(96, 100).reverse().join("")),
75
+ 'discharges_amph_count': HexTo10Str(t.slice(100, 104).reverse().join("")),
76
+ */
77
+ this.addMetadatum('measuredTotalVoltage','V', 'measured total voltage',
78
+ (buff)=>{return buff.readUInt32LE(8)/1000})
79
+
80
+ this.addDefaultPath('voltage', "electrical.batteries.voltage")
81
+ .read=(buff)=>{return buff.readUInt32LE(12)/1000}
82
+
83
+ for(let cellNum=0; cellNum < this?.numberOfCells??4; cellNum++) {
84
+ this.addMetadatum(`cell${cellNum+1}Voltage`,'V', `cell #${cellNum+1} voltage`,
85
+ (buff)=>{return buff.readInt16LE(16+(cellNum*2)) })
86
+ .default=`electrical.batteries.{batteryID}.cells.${cellNum+1}.voltage`
87
+ }
88
+
89
+ this.addDefaultPath('current','electrical.batteries.current')
90
+ .read=(buff)=>{return buff.readInt32LE(48)/1000}
91
+
92
+ this.addMetadatum('cellTemp','K', 'cell temperature',
93
+ (buff)=>{return buff.readInt16LE(52) + 273.15})
94
+ .default="electrical.batteries.{batteryID}.cells.temperature"
95
+
96
+ this.addMetadatum('bmsTemp','K', 'bms temperature',
97
+ (buff)=>{return buff.readInt16LE(54) + 273.15})
98
+ .default="electrical.batteries.{batteryID}.bms.temperature"
99
+
100
+ this.addDefaultPath('remainingAh','electrical.batteries.capacity.remaining')
101
+ .read=(buff)=>{return this.buff.readUInt16LE(62)/100}
102
+
103
+ this.addDefaultPath('actualAh','electrical.batteries.capacity.actual')
104
+ .read=(buff)=>{return this.buff.readUInt16LE(64)/100}
105
+
106
+ this.addMetadatum('heat','', 'discharge disabled due to app button = 00000080, heater_error = 00000002',
107
+ (buff)=>{return buff.slice(68,72).reverse().join("")})
108
+ .default="electrical.batteries.{batteryID}.heat"
109
+
110
+ this.addMetadatum('balanceMemoryActive','', 'activates when the battery has saved information about what cell it will balance',
111
+ (buff)=>{return buff.slice(72,76).reverse().join("")})
112
+ .default="electrical.batteries.{batteryID}.balanceMemoryActive"
113
+
114
+ this.addMetadatum('protectionState','', 'protection state',
115
+ (buff)=>{return buff.slice(76,80).reverse().join("")})
116
+ .default="electrical.batteries.{batteryID}.protectionState"
117
+
118
+ this.addMetadatum('failureState','', 'failure state',
119
+ (buff)=>{return buff.slice(80,84).reverse().join("").slice(-3)})
120
+ .default="electrical.batteries.{batteryID}.failureState"
121
+
122
+ this.addMetadatum('balanceState','', '1 = cell at offset is balancing',
123
+ (buff)=>{return buff.slice(84,88).reverse().join("")})
124
+ .default="electrical.batteries.{batteryID}.balanceState"
125
+
126
+ this.addMetadatum('batteryState','', 'charge disabled = "0004", charging = "0001" (when charging active app will show estimated time untill fully charged), discharging/idle: "0000", unkown = "0002"',
127
+ (buff)=>{return buff.slice(88,90).reverse().join("")})
128
+ .default="electrical.batteries.{batteryID}.batteryState"
129
+
130
+ this.addMetadatum('dischargeCount','', 'discharge count',
131
+ (buff)=>{return buff.readUInt32LE(96)})
132
+ .default="electrical.batteries.{batteryID}.dischargeCount"
133
+
134
+ this.addMetadatum('dischargeAhCount','', 'discharge ah count',
135
+ (buff)=>{return buff.readUInt32LE(100)})
136
+ .default="electrical.batteries.{batteryID}.dischargeAhCount"
137
+
138
+ this.addDefaultPath( 'soc',"electrical.batteries.capacity.stateOfCharge")
139
+ .read=(buff)=>{return buff.readUInt16LE(90)/100}
140
+
141
+
142
+ this.getJSONSchema().properties.params.required=["batteryID", "numberOfCells" ]
143
+ }
144
+
145
+ async initGATTConnection(){
146
+
147
+ return new Promise((resolve,reject )=>{
148
+ this.deviceConnect().then(async ()=>{
149
+ if (!this.gattServer) {
150
+ this.gattServer = await this.device.gatt()
151
+ this.service = await this.gattServer.getPrimaryService("0000ffe0-0000-1000-8000-00805f9b34fb")
152
+ this.rxCharacteristic = await this.service.getCharacteristic("0000ffe1-0000-1000-8000-00805f9b34fb")
153
+ this.txCharacteristic = await this.service.getCharacteristic("0000ffe2-0000-1000-8000-00805f9b34fb")
154
+ }
155
+ resolve(this)
156
+ })})
157
+ }
158
+ async initGATTNotifications() {
159
+ await this.txCharacteristic.writeValue( Buffer.from(this.constructor.Commands.query_battery_status))
160
+ await this.rxCharacteristic.startNotifications()
161
+ this.rxCharacteristic.on('valuechanged', buffer => {
162
+ this.emitValuesFrom(buffer)
163
+ })
164
+ }
165
+
166
+ async stopListening(){
167
+ super.stopListening()
168
+ if (this.rxCharacteristic && await this.rxCharacteristic.isNotifying()) {
169
+ await this.rxCharacteristic.stopNotifications()
170
+ this.rxCharacteristic=null
171
+ }
172
+ if (await this.device.isConnected()){
173
+ await this.device.disconnect()
174
+ }
175
+ }
176
+ }
177
+ module.exports=ShenzhenLiONBMS