diff --git a/src/bin/BinSettings.tsx b/src/bin/BinSettings.tsx index c65bd31..237a540 100644 --- a/src/bin/BinSettings.tsx +++ b/src/bin/BinSettings.tsx @@ -485,7 +485,6 @@ export default function BinSettings(props: Props) { form.inventory.inventoryControl = inventoryControl form.inventory.autoThreshold = autoFillThreshold } - console.log(form) binAPI .updateBin(bin.key(), form, as) .then(response => { diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx index 767eaed..af4184b 100644 --- a/src/bin/BinVisualizerV2.tsx +++ b/src/bin/BinVisualizerV2.tsx @@ -2194,6 +2194,7 @@ export default function BinVisualizer(props: Props) { ([]) @@ -62,6 +69,9 @@ export default function ModeChangeDialog(props: Props){ const [ambients, setAmbients] = useState([]) const [heaters, setHeaters] = useState([]) const [fans, setFans] = useState([]) + const [selectedPreset, setSelectedPreset] = useState(undefined); + const grainExtensionMap = GetGrainExtensionMap(); + //get the interactions and components for the device when it is selected from the dropdown useEffect(()=>{ if (!binKey) return; @@ -85,6 +95,7 @@ export default function ModeChangeDialog(props: Props){ newDComponents.push(c); dComponents.set(deviceNumber.toString(), newDComponents); }); + console.log(dComponents) setDeviceComponents(dComponents); setExistingInteractions(interactionResp); }) @@ -141,9 +152,266 @@ if (!selectedDevice) return; setOptions(o); }, [devices, setOptions]); + const buildHeaterInteraction = ( + sensor: Plenum | Ambient, + heater: Controller + ): pond.InteractionSettings => { + let interaction = pond.InteractionSettings.create({ + source: sensor.location(), + sink: heater.location(), + schedule: pond.InteractionSchedule.create({ + timeOfDayStart: "00:00", + timeOfDayEnd: "24:00", + timezone: moment.tz.guess(), + weekdays: moment.weekdays().map(d => lowerCase(d)) + }), + notifications: pond.InteractionNotifications.create({ + reports: true + }), + result: pond.InteractionResult.create({ + type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE, + value: 1 + }) + }); + + let temp = 0; + let hum = 0; + + //if a preset was selected use its temp/hum values + if (selectedPreset !== undefined) { + temp = selectedPreset.temp(); + hum = selectedPreset.hum(); + } else { + //otherwise use default values + switch(binMode){ + case pond.BinMode.BIN_MODE_COOLDOWN: + temp = 10 + hum = 45 + break; + case pond.BinMode.BIN_MODE_DRYING: + if(grain){ + //get the values using the grain type + let ext = grainExtensionMap.get(grain) + if (ext) { + temp = ext.setTempC + hum = ext.targetMC + } + }else{//otherwise use the default drying interaction + temp = 40 + hum = 20 + } + } + } + + let conditions = []; + let humidityCondition = pond.InteractionCondition.create({ + measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, + comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN, + value: Math.round( + describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, + sensor.settings.type, + sensor.settings.subtype + ).toStored(hum) + ) + }); + conditions.push(humidityCondition); + + //since the measurement describers function to stored does a conversion into celsius if the users pref is fahrenheit for temperature we need to convert the preset value into fahrenheit + if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { + temp = Math.round((temp * (9 / 5) + 32) * 100) / 100; + } + let tempVal = describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, + sensor.settings.type, + sensor.settings.subtype + ).toStored(temp); + + let tempCondition = pond.InteractionCondition.create({ + measurementType: quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, + comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN, + value: Math.round(tempVal) //and then round the converted value since interaction conditions wont take floats + }); + conditions.push(tempCondition); + interaction.conditions = conditions; + + return interaction; + }; + + const buildFanInteraction = ( + sensor: Plenum | Ambient, + fan: Controller, + tempComparison: "greater" | "less", + humidityComparison: "greater" | "less" + ) => { + let interaction = pond.InteractionSettings.create({ + source: sensor.location(), + sink: fan.location(), + schedule: pond.InteractionSchedule.create({ + timeOfDayStart: "00:00", + timeOfDayEnd: "24:00", + timezone: moment.tz.guess(), + weekdays: moment.weekdays().map(d => lowerCase(d)) + }), + notifications: pond.InteractionNotifications.create({ + reports: true + }), + result: pond.InteractionResult.create({ + type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE, + value: 1 + }) + }); + + let tempPreset = 0; + let humidityPreset = 0; + + //if a custom preset was selected use it + if (selectedPreset !== undefined) { + tempPreset = selectedPreset.temp(); + humidityPreset = selectedPreset.hum(); + } else { + //otherwise use one of the defaults + switch (binMode) { + case pond.BinMode.BIN_MODE_COOLDOWN: + tempPreset = 15; + humidityPreset = 60; + break; + case pond.BinMode.BIN_MODE_DRYING: + if(grain){ + //get the values using the grain type + let ext = grainExtensionMap.get(grain) + if (ext) { + tempPreset = ext.setTempC + humidityPreset = ext.targetMC + } + }else{//otherwise use the default drying interaction + tempPreset = 40 + humidityPreset = 20 + } + break; + case pond.BinMode.BIN_MODE_HYDRATING: + tempPreset = 25; + humidityPreset = 60; + break; + } + } + + let conditions = []; + let fanConditionOne = pond.InteractionCondition.create({ + measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, + comparison: + humidityComparison === "greater" + ? quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN + : quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN, + value: describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, + sensor.settings.type, + sensor.settings.subtype + ).toStored(humidityPreset) + }); + conditions.push(fanConditionOne); + + //since the measurement describers function toStored does a conversion into celsius for temperature if the users pref is fahrenheit we need to convert the preset value into fahrenheit + if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { + tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100; + } + let tempVal = describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, + sensor.settings.type, + sensor.settings.subtype + ).toStored(tempPreset); + + let fanConditionTwo = pond.InteractionCondition.create({ + measurementType: quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, + comparison: + tempComparison === "greater" + ? quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN + : quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN, + value: Math.round(tempVal) //and then round the converted value since the interaction does not take decimals + }); + conditions.push(fanConditionTwo); + + interaction.conditions = conditions; + return interaction; + }; + + //function to loop through the interaction sets building the settings const createInteractions = () => { + if(!selectedDevice) return //if there is no device that was selected, do nothing + let multiInteractionSettings: pond.MultiInteractionSettings = pond.MultiInteractionSettings.create() + let linkedComponents = deviceComponents.get(selectedDevice.id().toString()); + //loop through the sets + componentSets.forEach(async (set) => { + //loop through the controllers + set.controllers.forEach(controller => { + //filter the conflicting interactions for that controller + let conflictingInteractions = existingInteractions.filter(i => { + let conflicting = false; + if (linkedComponents) { + linkedComponents.forEach(comp => { + if (sameComponentID(comp.location(), i.settings.sink)) { + conflicting = true; + } + }); + } + return conflicting; + }); + //create an array of promises to delete them + let deleteConflictingInteractions = conflictingInteractions.map(i => { + return interactionAPI.removeInteraction(selectedDevice.id(), i.key(), as); + }); + //execute the promises + Promise.all([...deleteConflictingInteractions]).finally(() => { + //and one they are done make the new interaction to be added for the sensor and controller pair + switch(binMode){ + case pond.BinMode.BIN_MODE_COOLDOWN: + // if the controller is a heater create heater interaction + if(controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_HEATER){ + multiInteractionSettings.interactions.push(buildHeaterInteraction(set.sensor, controller)) + }else if(controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_AERATION_FAN || + controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_EXHAUST_FAN){ + // if the controller is a fan create a fan interaction + multiInteractionSettings.interactions.push(buildFanInteraction(set.sensor, controller, "less", "less")) + } + break; + case pond.BinMode.BIN_MODE_DRYING: + // if the controller is a heater create heater interaction + if(controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_HEATER){ + multiInteractionSettings.interactions.push(buildHeaterInteraction(set.sensor, controller)) + }else if(controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_AERATION_FAN || + controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_EXHAUST_FAN){// if the controller is a fan + //if it is a combination set using a heater as well just turn the fan on + if(set.combo){ + controller.settings.defaultOutputState = quack.OutputMode.OUTPUT_MODE_ON + }else{ + //otherwise make a fan interaction + multiInteractionSettings.interactions.push(buildFanInteraction(set.sensor, controller, "greater", "less")) + } + } + break; + case pond.BinMode.BIN_MODE_HYDRATING: + //check to make sure the controller is a fan, you cant hydrate with a heater, if the controller is a heater then it will not add an interaction + if(controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_AERATION_FAN || + controller.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_EXHAUST_FAN){ + //create fan interaction + multiInteractionSettings.interactions.push(buildFanInteraction(set.sensor, controller, "less", "greater")) + } + break; + } + console.log(multiInteractionSettings) + }) + + }) + }) + //add all of the interactions that were created (multiInteraction) + interactionAPI.addMultiInteractions(selectedDevice.id(), multiInteractionSettings).then(resp => { + //then once the interactions are added update the controllers to the proper states + + }).catch(err => { + //there was a problem adding the interactions + }) } const deviceSelector = () => { @@ -246,6 +514,7 @@ if (!selectedDevice) return; updateSets={(sets) => { //update the component sets that will be used for the interactions console.log(sets) + setComponentSets(sets) }}/> @@ -255,8 +524,8 @@ if (!selectedDevice) return; Cancel