bt-sensors-plugin-sk 1.2.0-beta.0.1.6 → 1.2.1

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.
Files changed (46) hide show
  1. package/BTSensor.js +45 -11
  2. package/README.md +184 -78
  3. package/Screenshot 2025-06-12 at 9.33.57/342/200/257AM.png +0 -0
  4. package/index.js +43 -51
  5. package/package.json +8 -7
  6. package/plugin_defaults.json +14 -5
  7. package/public/159.js +2 -1
  8. package/public/681.js +14 -0
  9. package/public/{239.js.LICENSE.txt → 681.js.LICENSE.txt} +9 -0
  10. package/public/847.js +1 -0
  11. package/public/images/Aranet2_HOME_F_900x900_90OVA5J.original.webp +0 -0
  12. package/public/images/BMV-712-Smart-Front.webp +0 -0
  13. package/public/images/Gobius_C.png +0 -0
  14. package/public/images/LYWSD03MMC-Device.jpg +0 -0
  15. package/public/images/Victron-SmartShunt.jpg +0 -0
  16. package/public/images/bluetooth-logo.png +0 -0
  17. package/public/images/smartsolarMPPT7515.png +0 -0
  18. package/public/images/victron-min-1.jpg +0 -0
  19. package/public/main.js +1 -1
  20. package/public/remoteEntry.js +1 -1
  21. package/sensor_classes/ATC.js +22 -1
  22. package/sensor_classes/BlackListedDevice.js +10 -7
  23. package/sensor_classes/GobiusCTankMeter.js +18 -1
  24. package/sensor_classes/JBDBMS.js +67 -39
  25. package/sensor_classes/RenogyRoverClient.js +0 -1
  26. package/sensor_classes/ShellySBMO003Z.js +4 -0
  27. package/sensor_classes/ShenzhenLiOnBMS.js +177 -0
  28. package/sensor_classes/Victron/VictronConstants.js +17 -32
  29. package/sensor_classes/Victron/VictronImages.js +8 -0
  30. package/sensor_classes/Victron/VictronSensor.js +27 -3
  31. package/sensor_classes/VictronBatteryMonitor.js +4 -0
  32. package/sensor_classes/VictronSolarCharger.js +1 -0
  33. package/sensor_classes/XiaomiMiBeacon.js +5 -0
  34. package/src/components/PluginConfigurationPanel.js +145 -60
  35. package/src/images/Aranet2_HOME_F_900x900_90OVA5J.original.webp +0 -0
  36. package/src/images/BMV-712-Smart-Front.webp +0 -0
  37. package/src/images/Gobius_C.png +0 -0
  38. package/src/images/LYWSD03MMC-Device.jpg +0 -0
  39. package/src/images/Victron-SmartShunt.jpg +0 -0
  40. package/src/images/bluetooth-logo.png +0 -0
  41. package/src/images/smartsolarMPPT7515.png +0 -0
  42. package/src/images/victron-min-1.jpg +0 -0
  43. package/webpack.config.js +1 -1
  44. package/public/239.js +0 -14
  45. package/public/778.js +0 -2
  46. /package/public/{778.js.LICENSE.txt → 159.js.LICENSE.txt} +0 -0
@@ -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")))))}}}]);
Binary file
Binary file
Binary file
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,12 +71,13 @@ class JBDBMS extends BTSensor {
62
71
  (buffer)=>{return buffer.readUInt8(24)} )
63
72
  .default="electrical.batteries.{batteryID}.FETControl"
64
73
 
65
- await this.deviceConnect()
74
+ await this.deviceConnect()
66
75
  const gattServer = await this.device.gatt()
67
76
  const txRxService= await gattServer.getPrimaryService(this.constructor.TX_RX_SERVICE)
68
77
  this.rxChar = await txRxService.getCharacteristic(this.constructor.NOTIFY_CHAR_UUID)
69
78
  this.txChar = await txRxService.getCharacteristic(this.constructor.WRITE_CHAR_UUID)
70
79
  await this.rxChar.startNotifications()
80
+
71
81
  const cellsAndTemps = await this.getNumberOfCellsAndTemps()
72
82
  this.numberOfCells=cellsAndTemps.cells
73
83
  this.numberOfTemps=cellsAndTemps.temps
@@ -84,58 +94,75 @@ class JBDBMS extends BTSensor {
84
94
  this.addMetadatum(`cell${i}Voltage`, 'V', `Cell ${i+1} voltage`,
85
95
  (buffer)=>{return buffer.readUInt16BE((4+(i*2)))/1000} )
86
96
  .default=`electrical.batteries.{batteryID}.cell${i}.voltage`
87
- this.addMetadatum(`cell${i}Balance`, 'V', `Cell ${i+1} balance` )
97
+ this.addMetadatum(`cell${i}Balance`, '', `Cell ${i+1} balance` )
88
98
  .default=`electrical.batteries.{batteryID}.cell${i}.balance`
89
99
 
90
100
  }
91
101
  }
102
+
92
103
  hasGATT(){
93
104
  return true
94
105
  }
95
-
96
- async initGATTNotifications(){
97
- this.intervalID = setInterval(()=>{
98
-
99
- this.emitGATT()
106
+ initGATTNotifications(){
107
+ this.intervalID = setInterval( async ()=>{
108
+ await this.emitGATT()
100
109
  }, 1000*(this?.pollFreq??60) )
101
110
  }
102
111
 
103
- emitGATT(){
104
- this.getAndEmitBatteryInfo()
105
- setTimeout(()=>{this.getAndEmitCellVoltages()}, 10000)
106
- }
107
-
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
+ }
108
126
 
109
127
  async getNumberOfCellsAndTemps(){
110
- var b = await this.getBuffer(0x3)
128
+ const b = await this.getBuffer(0x3)
111
129
  return {cells:b[25], temps:b[26]}
112
130
  }
113
131
 
114
132
 
115
- getBuffer(command){
133
+ getBuffer (command){
116
134
 
117
135
  return new Promise( async ( resolve, reject )=>{
118
136
  const r = await this.sendReadFunctionRequest(command)
119
- const result = Buffer.alloc(256)
120
- var offset = 0
121
-
137
+ let result = Buffer.alloc(256)
138
+ let offset = 0
139
+ let datasize = -1
122
140
  const timer = setTimeout(() => {
123
141
  clearTimeout(timer)
124
142
  reject(new Error(`Response timed out from JBDBMS device ${this.getName()}. `));
125
143
  }, 30000);
126
144
 
127
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
+ }
128
152
  buffer.copy(result,offset)
129
- 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)
130
156
  this.debug(result)
131
157
  this.rxChar.removeAllListeners()
132
158
  clearTimeout(timer)
159
+ if (!checkSum(result))
160
+ reject(`Invalid checksum from ${this.getName()}, not processing.`)
161
+
133
162
  resolve(result)
134
163
  }
135
164
  offset+=buffer.length
136
165
  }
137
-
138
-
139
166
  this.rxChar.on('valuechanged', valChanged )
140
167
  })
141
168
  }
@@ -144,8 +171,8 @@ async initGATTConnection() {
144
171
  return this
145
172
  }
146
173
 
147
- getAndEmitBatteryInfo(){
148
- this.getBuffer(0x03).then((buffer)=>{
174
+ async getAndEmitBatteryInfo(){
175
+ return this.getBuffer(0x03).then((buffer)=>{
149
176
  (["current", "voltage", "remainingCapacity", "capacity","cycles", "protectionStatus", "SOC","FET",]).forEach((tag) =>
150
177
  this.emitData( tag, buffer )
151
178
  )
@@ -160,9 +187,10 @@ getAndEmitBatteryInfo(){
160
187
  })
161
188
  }
162
189
 
163
- getAndEmitCellVoltages(){
164
- this.getBuffer(0x4).then((buffer)=>{
165
- 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++){
166
194
  this.emitData(`cell${i}Voltage`,buffer)
167
195
  }})
168
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