@wethecurious/iotes-curios

0.1.33 • Public • Published

iotes-curios

This collection of middlewares is designed to provide a redux friendly connection to We The Curious's Curios services for exhibit's implementing the redux pattern. The middleware handles connection to and data retrival from:

  • mqtt iot devices
  • phidget physical input devices
  • exhibit analytics service

Example

There is a basic example here of the usage of this package avaliable on We The Curious bitbucket https://bitbucket.org/wethecurious/playground-usecurios-example/src/master/

Usage

The createCuriosMiddleware export both a middleware and wrapped version of the redux combineReducer function which provides the '@@Curios' reducer to track connection state in the redux store

This is a significant rewrite of the previous brightsign-middleware package. In the long tun it will make it easer to intgrate new devices

Config example

const phidgetTopologoy: TopologyMap<PhidgetStrategyConfig, PhidgetDeviceTypes > = {
  hosts: [{ name: 'testapp/0', host: 'localhost', port: '8888' }],
  devices: [
      {
          hostName: 'testapp/0', //host name of device matches the device with required host
          type: 'RFID_READER',
          name: 'READ/1', // Note that the names must be unique globally across all strategies at this stage
          channel: 1,
      },
      {
          hostName: 'testapp/0',
          type: 'ROTARY_ENCODER',
          name: 'ENCOD/1',
          channel: 2,
      },
  ],
}

const messageTopologoy: TopologyMap<MqttStrategyConfig, MqttDeviceTypes> = {
    hosts: [{ name: 'testapp/0', host: 'localhost', port: '8888' }],
    devices: [
        {
            hostName: 'testapp/0',
            type: 'APP_CHANNEL',
            name: 'READER/1',
            channel: 1,
        },
        {
            hostName: 'testapp/0',
            type: 'EXTERNAL_CHANNEL',
            name: 'ENCODER/1',
            channel: 2,
        },
    ],
  }

const config: CuriosConfig = {
    app: 'app',
    appInstance: 0,
    service: 'service',
    serviceInstance: 0,
    phidget: phidgetTopologoy,
    message: messageTopologoy
} 

Usage example

On Initialisation

const { useCurios, middleware, combineReducers }: CuriosIntegration = createCuriosMiddleware(config)
const reduxStore = createStore(combineReducers({...otherReducers}), applyMiddleware(...middleware))

Within a component

const Component = () => {
  const [ deviceVal, setDeviceVal ] = useCurios()

  return (
      <>
        <p>{deviceVal}</p>
        <button onClick={() => {
          setDeviceVal(
            'ENCODER/1', // Device name to update 
            'UPDATE', // type of update (may not be used by the strategy, depending on the purpose and docs)
            { message: 'test' }, // Payload to send to device
          )
        }}
        />
      </>
  )
}

Adding Devices

Adding Strategies to handle new device types

This is packages is built on iotes, which is a more generalised packages for communication between state management libraries.

Iotes works by routing requests to strategies which hendle device communication. The strategy for phidget22 for example for be found here

https://www.npmjs.com/package/iotes-strategy-phidget22,

support for more more devices can be added by modifying the strategy source or writing a new strategy

The general form of a strategy is as follows

 const strategy = iotesFunctions => hostFactory => DeviceFactory => DeviceFunction

For example

const phidgetStrategy = (
    hostDispatch,
    deviceDispatch,
    hostSubscribe,
    hostDispatch
): HostFactory => async (
    hostConfig: HostConfig<StrategyConfig>,
): Promise<DeviceFactory> => (
    deviceFactory
) => DeviceFunctions

The function of each of the stages is:

  • iotesFunction: is where the iotes commuication channel are injected and should remain as the four fuctions as demonstrated.
  • hostFactory: is where the host connections from the tolopology map are created. This is where you make the connection to the service you are trying to use. This returns a device factory.
  • deviceFactory: This returns a object of functions. Each function create connections to the devices described in the topology map.
  • deviceFunctions: This is the function which creates the connection to the actual device.

The completed strategy should then be able to be passed into the createIotes function and be initialised according to the topology map

Adding strategies to Curios reducer

The reducer connection to iotes is initialised by creating muliple instances of the IotesReactReduxHooks plugin.

  const [ usePhidget, phidgetMiddleware ]: IotesReactReduxHook = createIotesReactReduxHook(
    {...phidget, client: { name: names.complete }}, 
    phidgetStrategy, '@@CURIOS', '@@CURIOS_PHIDGET'
  )
  const [ useMessage, messageMiddleware ]: IotesReactReduxHook = createIotesReactReduxHook(
    { ...message, client: { name: names.complete } }, 
    mqttStrategy, '@@CURIOS', '@@CURIOS_MESSAGE'
  )
  const [ useAnalytics, analyticsMiddleware ]: IotesReactReduxHook = createIotesReactReduxHook(
    {...analytics, client: { name: names.complete }}, 
    mqttStrategy, '@@CURIOS', '@@CURIOS_ANALYTICS'
  )
  //Add a new connection here

  const middlewares = [phidgetMiddleware, messageMiddleware, analyticsMiddleware, /*Add new  middleware here*/]

  return ({
    useCurios: createUseCurios(usePhidget, useMessage, useAnalytics, /*add new hooks here*/), 
    middleware: middlewares, 
    combineReducers
  })

In the actual custom hook you need to manually add the hook handlng at this stage (I couldn't work out how to reliably put it in a loop without violating the rules of hooks)

const createUseCurios = (usePhidget: any, useMessage: any, useAnalytics: any):() => [{}, any] => {
    return () => {
      const [ input, setInput ] = useState({})
      const [ phidget, setPhidget ] = usePhidget()
      const [ message, setMessage ] = useMessage()
      const [ analytics, setAnalytics ] = useAnalytics()
      // Destructure new hooks here 
      const [ output, setOutput ] = useState<DeviceDispatchable<any>>({})

      const setDeviceVal = (
        name: string,
        type: any,
        payload: {[key:string] : unknown},
        meta?: {[key:string] : unknown}, 
        source? :string,
        error?: ErrorDispatchable
      ) => {
        setOutput({...output, ... createDeviceDispatchable(name, type, payload, meta, source, error)})
      }

      useEffect(() => { 
        setInput(phidget) 
      }, [phidget])

      useEffect(() => { 
        setInput(message) 
      }, [message])

      useEffect(() => { 
        setInput(analytics) 
      }, [analytics])

      // Add input method here

      useEffect(() => {
        setMessage(output)
        setPhidget(output)
        // add set hook here
      },[output])

      return [ input, setDeviceVal ]
    }
}

TODO

  • Support for more phidget devices
  • Strategy to talk to mqtt dmx

Readme

Keywords

none

Package Sidebar

Install

npm i @wethecurious/iotes-curios

Weekly Downloads

0

Version

0.1.33

License

MIT

Unpacked Size

21.7 kB

Total Files

11

Last publish

Collaborators

  • nestorreta
  • makorantz
  • benvium