diff --git a/apps/electron-app/src/common/nodes.ts b/apps/electron-app/src/common/nodes.ts index 9f8f1d7..1738e3a 100644 --- a/apps/electron-app/src/common/nodes.ts +++ b/apps/electron-app/src/common/nodes.ts @@ -22,6 +22,7 @@ import { Delay } from '../render/components/react-flow/nodes/Delay'; import { Calculate } from '../render/components/react-flow/nodes/Calculate'; import { Constant } from '../render/components/react-flow/nodes/Constant'; import { Relay } from '../render/components/react-flow/nodes/Relay'; +import { Switch } from '../render/components/react-flow/nodes/Switch'; export const NODE_TYPES: Record JSX.Element> = { Button: Button, @@ -49,6 +50,7 @@ export const NODE_TYPES: Record JSX.Element> = { Rgb: Rgb, Servo: Servo, Smooth: Smooth, + Switch: Switch, Trigger: Trigger, Vibration: Vibration, } as const; diff --git a/apps/electron-app/src/render/components/react-flow/nodes/Switch.tsx b/apps/electron-app/src/render/components/react-flow/nodes/Switch.tsx new file mode 100644 index 0000000..256e85b --- /dev/null +++ b/apps/electron-app/src/render/components/react-flow/nodes/Switch.tsx @@ -0,0 +1,72 @@ +import { SwitchData, SwitchValueType } from '@microflow/components'; +import { BaseNode, NodeContainer, useNodeSettings } from './Node'; +import { Handle } from './Handle'; +import { Position } from '@xyflow/react'; +import { useNodeValue } from '../../../stores/node-data'; +import { Switch as UiSwitch } from '@ui/index'; +import { useEffect } from 'react'; +import { usePins } from '../../../stores/board'; +import { MODES } from '../../../../common/types'; +import { mapPinToPaneOption } from '../../../../utils/pin'; + +export function Switch(props: Props) { + return ( + + + + + + + + ); +} + +function Value() { + const value = useNodeValue(false); + + return ; +} + +function Settings() { + const { pane, settings } = useNodeSettings(); + const pins = usePins(); + + useEffect(() => { + if (!pane) return; + + const pinBinding = pane.addBinding(settings, 'pin', { + view: 'list', + disabled: !pins.length, + label: 'pin', + index: 0, + options: pins.filter(pin => pin.supportedModes.includes(MODES.INPUT)).map(mapPinToPaneOption), + }); + + const typeBinding = pane.addBinding(settings, 'type', { + view: 'list', + label: 'type', + index: 1, + options: [ + { value: 'NC', text: 'normally closed' }, + { value: 'NO', text: 'normally open' }, + ], + }); + + return () => { + pinBinding.dispose(); + typeBinding.dispose(); + }; + }, [pins, pane, settings]); + return null; +} + +type Props = BaseNode; +Switch.defaultProps = { + data: { + pin: 2, + group: 'hardware', + label: 'Switch', + tags: ['digital', 'input'], + type: 'NC', + } satisfies Props['data'], +}; diff --git a/apps/nextjs-app/app/docs/microflow-studio/nodes/hardware/switch/page.md b/apps/nextjs-app/app/docs/microflow-studio/nodes/hardware/switch/page.md new file mode 100644 index 0000000..65b1af5 --- /dev/null +++ b/apps/nextjs-app/app/docs/microflow-studio/nodes/hardware/switch/page.md @@ -0,0 +1,48 @@ +--- +title: Switch +--- + +{% tags %} +{% tag title="Digital" /%} +{% tag title="Input" /%} +{% /tags %} + +Similar to a [`Button`](/docs/microflow-studio/nodes/hardware/button), a switch is a simple input device that can be either open or closed. + +In comparison, a switch will hold its state until it is changed, while a button will only be active while it is being pressed. + +{% iframe src="https://www.tinkercad.com/embed/dxxCQPOmd5e" /%} + +## Types of switches + +Switches come in many shapes and sizes. Below are a few examples and how to wire them up. + +{% callout type="note" title="Wiring" %} +The wiring examples are for illustrative purposes, it might not work with your particular switch. +{% /callout %} + +**Is my button active table** +| Switch Type | Switch State | Input Pin State | +|-------------|--------------|-----------------| +| Normally Open (NO) | On | HIGH (1) | +| Normally Open (NO) | Off | LOW (0) | +| Normally Closed (NC) | On | LOW (0) | +| Normally Closed (NC) | Off | HIGH (1) | + +### 2 pin on-off switch + +A 2 pin switch requires a _resistor_ to work properly. + +![2 pin on-off switch](/images/2-pin-on-off-switch.svg) + +### 3 pin on-off switch + +A 3 pin switch is similar to a 2 pin switch, it does not require a _resistor_ but it has an additional pin that is connected to the input pin. + +The input pin is usually connected to the middle pin, while the other two pins are connected to the ground and power. + +![3 pin switch](/images/3-pin-on-off-switch.svg) + +## Resources + +[Johnny-Five](https://johnny-five.io/api/switch/) diff --git a/apps/nextjs-app/lib/navigation.ts b/apps/nextjs-app/lib/navigation.ts index a050220..c7c5e56 100644 --- a/apps/nextjs-app/lib/navigation.ts +++ b/apps/nextjs-app/lib/navigation.ts @@ -59,6 +59,11 @@ export const navigation = [ href: '/docs/microflow-studio/nodes/hardware/servo', parent: '/docs/microflow-studio/nodes/hardware', }, + { + title: 'Switch', + href: '/docs/microflow-studio/nodes/hardware/switch', + parent: '/docs/microflow-studio/nodes/hardware', + }, { title: 'Vibration', href: '/docs/microflow-studio/nodes/hardware/vibration', diff --git a/apps/nextjs-app/public/images/2-pin-on-off-switch.svg b/apps/nextjs-app/public/images/2-pin-on-off-switch.svg new file mode 100644 index 0000000..654f492 --- /dev/null +++ b/apps/nextjs-app/public/images/2-pin-on-off-switch.svg @@ -0,0 +1,10 @@ + + + + + + + + GNDSIG5Vonoff \ No newline at end of file diff --git a/apps/nextjs-app/public/images/3-pin-on-off-on-switch.svg b/apps/nextjs-app/public/images/3-pin-on-off-on-switch.svg new file mode 100644 index 0000000..7899394 --- /dev/null +++ b/apps/nextjs-app/public/images/3-pin-on-off-on-switch.svg @@ -0,0 +1,10 @@ + + + + + + + + GNDSIG5Vononoff \ No newline at end of file diff --git a/apps/nextjs-app/public/images/3-pin-on-off-switch.svg b/apps/nextjs-app/public/images/3-pin-on-off-switch.svg new file mode 100644 index 0000000..961e7bc --- /dev/null +++ b/apps/nextjs-app/public/images/3-pin-on-off-switch.svg @@ -0,0 +1,10 @@ + + + + + + + + GNDSIG5Vonoff \ No newline at end of file diff --git a/packages/components/index.ts b/packages/components/index.ts index 4128ab0..bb8a1b5 100644 --- a/packages/components/index.ts +++ b/packages/components/index.ts @@ -1,4 +1,4 @@ -export { Board } from 'johnny-five'; +export * from './src/TcpSerial'; export * from './src/components/Button'; export * from './src/components/Calculate'; export * from './src/components/Compare'; @@ -8,19 +8,20 @@ export * from './src/components/Delay'; export * from './src/components/Figma'; export * from './src/components/Gate'; export * from './src/components/Interval'; -export * from './src/components/Oscillator'; -export * from './src/components/Trigger'; -export * from './src/components/Smooth'; export * from './src/components/Led'; export * from './src/components/Matrix'; export * from './src/components/Monitor'; export * from './src/components/Motion'; export * from './src/components/Mqtt'; +export * from './src/components/Oscillator'; export * from './src/components/Piezo'; +export * from './src/components/RGB'; export * from './src/components/RangeMap'; export * from './src/components/Relay'; -export * from './src/components/RGB'; export * from './src/components/Sensor'; export * from './src/components/Servo'; +export * from './src/components/Smooth'; +export * from './src/components/Switch'; +export * from './src/components/Trigger'; export * from './src/types'; -export * from './src/TcpSerial'; +export { Board } from 'johnny-five'; diff --git a/packages/components/src/components/Switch.ts b/packages/components/src/components/Switch.ts new file mode 100644 index 0000000..a1edea1 --- /dev/null +++ b/packages/components/src/components/Switch.ts @@ -0,0 +1,59 @@ +import JohnnyFive, { SwitchOption } from 'johnny-five'; +import { BaseComponent, BaseComponentData } from './BaseComponent'; + +export type SwitchValueType = boolean; +export type SwitchData = Omit; + +export class Switch extends BaseComponent { + private component: JohnnyFive.Switch; + + constructor(data: BaseComponentData & SwitchData) { + super(data, false); + + this.component = new JohnnyFive.Switch(data); + + this.component.on('open', () => { + this.value = true; + this.eventEmitter.emit('open', this.value); + }); + + this.component.on('close', () => { + this.value = false; + this.eventEmitter.emit('close', this.value); + }); + } +} + +// TODO: when implementing a 3 pin on-off-on switch switch, check the following code. +// const switch1 = new Switch(2); // Switch component for ON1 terminal +// const switch2 = new Switch(3); // Switch component for ON2 terminal + +// switch1.on("open", () => { +// console.log("Switch is in OFF or ON2 position"); +// }); + +// switch1.on("close", () => { +// console.log("Switch is in ON1 position"); +// }); + +// switch2.on("open", () => { +// console.log("Switch is in OFF or ON1 position"); +// }); + +// switch2.on("close", () => { +// console.log("Switch is in ON2 position"); +// }); + +// // Function to determine the exact position of the switch +// const determineSwitchPosition = () => { +// if (switch1.isClosed) { +// console.log("Switch is in ON1 position"); +// } else if (switch2.isClosed) { +// console.log("Switch is in ON2 position"); +// } else { +// console.log("Switch is in OFF position"); +// } +// }; + +// // Check the switch position every 500ms +// setInterval(determineSwitchPosition, 500);