diff --git a/packages/protodevice/src/device/Device.ts b/packages/protodevice/src/device/Device.ts index 2dca02765..9bd285d1f 100644 --- a/packages/protodevice/src/device/Device.ts +++ b/packages/protodevice/src/device/Device.ts @@ -22,16 +22,23 @@ class Device { deviceComponents.esphome.name = deviceName deviceComponents.protofy = { credentials: this.credentials } - this.components?.forEach((component, i) => { - console.log("🚀 ~ file: Device.ts:62 ~ Device ~ this.components?.forEach ~ component:", component) - if(component){ - deviceComponents = component.attach( - !isNaN(parseInt(this.pinTable[i])) - ? parseInt(this.pinTable[i]) - : this.pinTable[i], deviceComponents, this.components - ); - } + this.components?.map((component, i) => ({ + component, + pin: !isNaN(parseInt(this.pinTable[i])) ? parseInt(this.pinTable[i]) : this.pinTable[i] + })) + // Sort to ensure "sd_card_component" types are attached last + .sort((a, b) => { + if (a.component?.type === "sd_card_component") return 1; + if (b.component?.type === "sd_card_component") return -1; + return 0; }) + // Attach each component in the sorted order with its associated pin + .forEach(({ component, pin }) => { + if (component) { + deviceComponents = component.attach(pin, deviceComponents, this.components); + } + }); + delete deviceComponents.protofy //console.log("🚀 ~ file: Device.ts:120 ~ Device ~ getComponents ~ deviceComponents:", deviceComponents) this.componentsTree = deviceComponents @@ -50,6 +57,12 @@ class Device { } } }) + + + + + + this.subsystemsTree = this.subsystemsTree.sort((a,b)=>{ if(a.name=="mqtt"){ return -1 diff --git a/packages/protodevice/src/device/SdOfflineLogger.ts b/packages/protodevice/src/device/SdOfflineLogger.ts new file mode 100644 index 000000000..c71dc22e7 --- /dev/null +++ b/packages/protodevice/src/device/SdOfflineLogger.ts @@ -0,0 +1,79 @@ +import { device } from "./Device"; + +class SdOfflineLogger { + name; + type; + timeId; + jsonFileName; + intervalSeconds; + publishDataWhenOnline; + publishDataTopic; + sensorsArray; + + constructor(name, timeId, jsonFileName, intervalSeconds, publishDataWhenOnline, publishDataTopic) { + this.name = name; + this.type = "sd_card_component"; + this.timeId = timeId; + this.jsonFileName = jsonFileName; + this.intervalSeconds = intervalSeconds; + this.publishDataWhenOnline = publishDataWhenOnline; + this.publishDataTopic = publishDataTopic; + this.sensorsArray = []; + } + + attach(pin, deviceComponents) { + deviceComponents?.sensor?.forEach((sensor) => { + if (sensor.name){ + this.sensorsArray.push(sensor.name); + } else if (sensor.id){ + this.sensorsArray.push(sensor.id); + } + }); + + const componentObjects = [ + { + name: "external_components", + config: { + //@ts-ignore + source: "github://Protofy-xyz/esphome-components", + refresh: "10s", + components: ["sd_card_component"] + } + }, + { + name: "sd_card_component", + config: { + id: this.name, + cs_pin: pin, + time_id: this.timeId, + json_file_name: this.jsonFileName, + interval_seconds: this.intervalSeconds, + publish_data_when_online: this.publishDataWhenOnline, + publish_data_topic: deviceComponents.mqtt?.topic_prefix+this.publishDataTopic, + sensors: this.sensorsArray, + }, + }, + ]; + + componentObjects.forEach((element) => { + if (!deviceComponents[element.name]) { + deviceComponents[element.name] = element.config; + } else { + if (!Array.isArray(deviceComponents[element.name])) { + deviceComponents[element.name] = [deviceComponents[element.name]]; + } + deviceComponents[element.name] = [...deviceComponents[element.name], element.config]; + } + }); + + return deviceComponents; + } + + getSubsystem() { + return {} + } +} + +export function sdOfflineLogger(name, timeId, jsonFileName, intervalSeconds, publishDataWhenOnline, publishDataTopic) { + return new SdOfflineLogger(name, timeId, jsonFileName, intervalSeconds, publishDataWhenOnline, publishDataTopic); +} diff --git a/packages/protodevice/src/device/index.ts b/packages/protodevice/src/device/index.ts index d3feee90d..21c17214e 100644 --- a/packages/protodevice/src/device/index.ts +++ b/packages/protodevice/src/device/index.ts @@ -50,4 +50,5 @@ export * from './MKSServo42D' export * from './Msa3xx' export * from './ODrive' export * from './INA226' -export * from './SntpTime' \ No newline at end of file +export * from './SntpTime' +export * from './SdOfflineLogger' \ No newline at end of file diff --git a/packages/protodevice/src/nodes/SdOfflineLogger.tsx b/packages/protodevice/src/nodes/SdOfflineLogger.tsx new file mode 100644 index 000000000..12ce392dd --- /dev/null +++ b/packages/protodevice/src/nodes/SdOfflineLogger.tsx @@ -0,0 +1,46 @@ +import React from "react"; +import { Node, Field, HandleOutput, NodeParams } from "protoflow"; +import { getColor } from "."; + +const SdOfflineLogger = ({ node = {}, nodeData = {}, children, color }: any) => { + const nameErrorMsg = 'Reserved name' + const [name, setName] = React.useState(nodeData['param-1']) + const intervalErrorMsg = 'Add units h/m/s/ms' + const nodeParams: Field[] = [ + { + label: 'Name', static: true, field: 'param-1', type: 'input', onBlur: () => { setName(nodeData['param-1']) }, + error: nodeData['param-1']?.value?.replace(/['"]+/g, '') == 'sd_card_component' ? nameErrorMsg : null + }, + { label: 'Time ID', static: true, field: 'param-2', type: 'input', }, + { label: 'JSON File Name', static: true, field: 'param-3', type: 'input' }, + { + label: 'Interval Seconds', static: true, field: 'param-4', type: 'input', + error: !['h', 'm', 's', 'ms'].includes(nodeData['param-4']?.value?.replace(/['"0-9]+/g, '')) ? intervalErrorMsg : null + }, + { label: 'Publish Data When Online', static: true, field: 'param-5', type: 'boolean' }, + { label: 'Publish Data Topic', static: true, field: 'param-6', type: 'input' }, + + ] as Field[] + return ( + + + + ) +} + +export default { + id: 'SdOfflineLogger', + type: 'CallExpression', + category: "Utils", + keywords: ["sd", "log", "offline"], + check: (node, nodeData) => node.type == "CallExpression" && nodeData.to?.startsWith('sdOfflineLogger'), + getComponent: (node, nodeData, children) => , + getInitialData: () => { return { to: 'sdOfflineLogger', + "param-1": { value: "", kind: "StringLiteral" }, + "param-2": { value: "", kind: "StringLiteral" }, + "param-3": { value: "/offline_data.json", kind: "StringLiteral" }, + "param-4": { value: "30s", kind: "StringLiteral" }, + "param-5": { value: true, kind: "FalseKeyword" }, + "param-6": { value: "/ofline_data", kind: "StringLiteral" }, + } } +} diff --git a/packages/protodevice/src/nodes/index.tsx b/packages/protodevice/src/nodes/index.tsx index 863cb50a6..2d27bfeb9 100644 --- a/packages/protodevice/src/nodes/index.tsx +++ b/packages/protodevice/src/nodes/index.tsx @@ -39,6 +39,7 @@ import ODrive from './ODrive'; import INA226 from './INA226'; import LEDCOutput from './LEDCOutput'; import SntpTime from './SntpTime'; +import SdOfflineLogger from './SdOfflineLogger'; const deviceMasks = [ @@ -81,6 +82,7 @@ const deviceMasks = [ INA226, LEDCOutput, SntpTime, + SdOfflineLogger, ] const masksLength = deviceMasks.length