kryten
Version:
A wrapper for johnny-five that lets you define/re-configure a board using JSON and then generates schemaform.io schema for controlling it.
280 lines (250 loc) • 8.91 kB
text/coffeescript
_ = require 'lodash'
five = require 'johnny-five'
Oled = require 'oled-js'
font = require 'oled-font-5x7'
debug = require('debug')('kryten')
util = require 'util'
EventEmitter = require('events').EventEmitter
SchemaGenerator = require './angular-schema-generator/index.coffee'
SchemaGenerator = new SchemaGenerator
KrytenSchema = require './kryten-schemas/index.coffee'
KrytenSchema = new KrytenSchema
class Kryten
constructor: (io={}) ->
EventEmitter.call @
= {interval: 1000}
= io
= {}
prevData = {}
= false
= false
()
()
util.inherits(@, EventEmitter)
StartBoard: (device) =>
= true
if !
if !device.autoDetect
if !.io?
= new five.Board({port: device.port, repl: false})
else
= new five.Board()
else
= new five.Board()
.on 'ready', =>
debug 'ready dude'
'ready'
= true
(device)
onMessage: (message) =>
payload = message if !message.payload?
payload = message.payload if message.payload?
payload.name = payload.component
if !.component[payload.name]
return
debug(.component[payload.name])
switch .component[payload.name].action
when 'digitalWrite'
value = parseInt(payload.state)
.digitalWrite(.component[payload.name].pin, value)
when "analogWrite"
value = payload.value
debug("analog STUFF", value)
debug("pinsssc", .component[payload.name].pin)
.analogWrite(parseInt(.component[payload.name].pin), value)
when "servo"
debug('servo', payload.name)
if payload.servo_action == "to"
value = payload.to_value
.servo[payload.name].stop()
.servo[payload.name].to(value)
else if payload.servo_action == "sweep"
.servo[payload.name].sweep([payload.sweep.min, payload.sweep.max])
else if payload.servo_action == "stop"
.servo[payload.name].stop()
when "PCA9685-Servo"
if payload.servo_action == "to"
value = payload.to_value
.servo[payload.name].stop()
.servo[payload.name].to(value)
else if payload.servo_action == "sweep"
.servo.sweep([payload.sweep.min, payload.sweep.max])
else if payload.servo_action == "stop"
.servo[payload.name].stop()
when "oled-i2c"
.oled[payload.name].turnOnDisplay()
.oled[payload.name].clearDisplay()
.oled[payload.name].update()
.oled[payload.name].setCursor(1, 1)
.oled[payload.name].writeString(font, 3, payload.text , 1, true)
when "LCD-PCF8574A"
.lcd[payload.name].clear()
if payload.text.length <= 16
.lcd[payload.name].cursor(0,0).noAutoscroll().print(payload.text)
else if payload.text.length > 16
.lcd[payload.name].cursor(0,0).print(payload.text.substring(0,16))
.lcd[payload.name].cursor(1,0).print(payload.text.substring(16,33))
when "LCD-JHD1313M1"
.lcd[payload.name].clear()
if payload.text.length <= 16
.lcd[payload.name].cursor(0,0).noAutoscroll().print(payload.text)
else if payload.text.length > 16
.lcd[payload.name].cursor(0,0).print(payload.text.substring(0,16))
.lcd[payload.name].cursor(1,0).print(payload.text.substring(16,33))
when "esc"
.esc[payload.name].speed(payload.speed)
checkConfig: (data) =>
if
return if _.isEqual(data, prevData)
if _.has(data, "components")
(data)
else if !_.has(data, "components")
debug 'No components'
return
prevData = data
configBoard: (data) =>
= data
debug 'board is',
if
()
components = .components
debug components
debug(components)
(components)
else
setTimeout ->
()
debug 'config'
,1000
createComponents: (comp) =>
_.forEach comp, (part) =>
debug(part)
debug
return if !_.has(part, "pin") && !_.has(part, "address")
if _.has(part, "pin")
.component[part.name] = {
pin: part.pin
action: part.action
}
if _.has(part, "address")
.component[part.name] = {
address: part.address,
action: part.action
}
debug(.component)
switch (part.action)
when 'digitalRead'
debug("digitalRead")
.pinMode(part.pin, five.Pin.INPUT)
.digitalRead part.pin, (value) =>
if _.has(.component, part.name)
.read[part.name] = value
when 'digitalWrite'
.pinMode(part.pin, .MODES.OUTPUT)
.names.push(part.name)
when 'analogRead'
.pinMode(part.pin, five.Pin.ANALOG)
.analogRead part.pin, (value) =>
if _.has(.component, part.name)
.read[part.name] = value
when 'analogWrite'
.pinMode(parseInt(part.pin), five.Pin.PWM)
.names.push(part.name)
when 'servo'
.servo[part.name] = new five.Servo({pin: parseInt(part.pin)})
.names.push(part.name)
when 'servo-continuous'
.servo[part.name] = new five.Servo.Continuous(parseInt(part.pin)).stop()
.names.push(part.name)
when 'PCA9685-Servo'
address = parseInt(part.address) || 0x40
.servo[part.name] = new five.Servo({
address: address,
controller: "PCA9685",
pin: part.pin
})
.names.push(part.name)
when 'oled-i2c'
debug("oled initiated")
address = parseInt(part.address) || 0x3C
opts = {
width: 128
height: 64
address: address
}
.oled[part.name] = new Oled(, five, opts)
.oled[part.name].clearDisplay()
.oled[part.name].setCursor(1, 1)
.oled[part.name].writeString(font, 3, 'Skynet Lives', 1, true)
.oled[part.name].update()
.names.push(part.name)
when 'LCD-PCF8574A'
.lcd[part.name] = new five.LCD({
controller: "PCF8574A",
rows: 2,
cols: 16
})
.lcd[part.name].cursor(0, 0).print("Skynet Lives")
.names.push(part.name)
when 'LCD-JHD1313M1'
.lcd[part.name] = new five.LCD({
controller: "JHD1313M1",
rows: 2,
cols: 16
})
.lcd[part.name].cursor(0, 0).print("Skynet Lives")
.names.push(part.name)
when 'MPU6050'
addr = parseInt(part.address) || 0x68
.accel[part.name] = new five.IMU({
controller: "MPU6050",
address: addr
})
.accel[part.name].on "data", (err, data) =>
values = {}
values["accel"] = {"x": this.accelerometer.x , "y": this.accelerometer.y, "z": this.accelerometer.z}
values["gyro"] = {"x": this.gyro.x , "y": this.gyro.y, "z": this.gyro.z}
values["temp"] = {"temperature" : this.temperature.celsius}
.read[part.name] = values
when 'esc'
.esc[part.name] = new five.ESC({
device: "FORWARD_REVERSE",
neutral: 50,
pin: part.pin
})
.names.push(part.name)
else null
schema = SchemaGenerator.generateMessageSchema(.names, .component)
krytenSchema = KrytenSchema.generateMessageSchema(.names, .component)
'angular-schema-form', schema
'schema', schema
'config', krytenSchema
debug schema
clearBoard: () =>
= {
names: []
component: {}
read: {}
servo: []
oled: []
lcd: []
accel: []
map: []
esc: []
}
debug
spareHead: (device={}) =>
(device)
configure: (device={}) =>
return unless device?
= device
(device) if !
(device)
Read: =>
debug("interval is:", .interval)
setInterval =>
return unless .read? && !_.isEmpty .read
debug .read
'data', .read
, .interval
module.exports = Kryten