Skip to content

Commit

Permalink
add support for Kuando Busylight
Browse files Browse the repository at this point in the history
  • Loading branch information
josephdadams committed Mar 19, 2024
1 parent 8fbbe36 commit 596bcfe
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# beacon

> Control a USB Busylight such as the Luxafor Flag or Thingm blink(1) as a Beacon/Notification via REST API or socket.io.
> Control a USB Busylight such as the Luxafor Flag, Thingm blink(1), or Kuando Busylight as a Beacon/Notification via REST API or socket.io.
For API information, see [api.md](api.md).

Expand Down
3 changes: 0 additions & 3 deletions config.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "beacon",
"productName": "beacon",
"version": "0.1.1",
"version": "0.2.0",
"description": "Control a USB Busylight as a Beacon/Notification",
"license": "MIT",
"repository": "josephdadams/beacon",
Expand All @@ -20,6 +20,8 @@
"release": "np"
},
"dependencies": {
"busylight": "^0.6.0",
"csscolorparser": "^1.0.3",
"electron-context-menu": "^3.0.0",
"electron-debug": "^3.2.0",
"electron-positioner": "^4.1.0",
Expand All @@ -30,10 +32,11 @@
"express": "^4.18.1",
"luxafor-api": "^4.0.0",
"node-blink1": "^0.5.1",
"node-hid": "^2.1.2",
"socket.io": "^4.5.1"
},
"devDependencies": {
"electron": "^12.0.6",
"electron": "^26.1.0",
"electron-builder": "^23.0.2",
"np": "^7.5.0",
"xo": "^0.39.1"
Expand Down
197 changes: 166 additions & 31 deletions util.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ const luxafor = require('luxafor-api');
//blink(1) library
const blink1 = require('node-blink1');

//busylight library
const busylight = require('busylight');

function setUpBeacons() {
global.DEVICES = [];
global.USB_DEVICES = 0;

detectScreens();
detectLuxafor();
detectBlink();
detectBusylight();

buildContextMenu();

Expand Down Expand Up @@ -86,6 +90,40 @@ function detectBlink() {
}
}

function detectBusylight() {
try {
let busylights = busylight.devices();
//loop through the devices and add them to the devices array
for (let i = 0; i < busylights.length; i++) {
//let busylightDevice = busylight.get(busylights[i].path);
let busylightDevice = busylight.get();
busylightDevice.path = busylights[i].path; //store the path for later use
busylightDevice.deviceId = 'busylight-' + (i+1); //busylight devices don't have a serial number
busylightDevice.deviceType = 'busylight';
busylightDevice.deviceName = 'Busylight ' + (i+1);

busylightDevice.defaultSettings = {
keepalive: true, // If the busylight is not kept alive it will turn off after 30 seconds
color: 'white', // The default color to use for light, blink and pulse
duration: 30 * 1000, // The duration for a blink or pulse sequence
rate: 300, // The rate at which to blink or pulse
degamma: true, // Fix rgb colors to present a better light
tone: 'OpenOffice', // Default ring tone
volume: 4 // Default volume
}; //store defaults to use later

busylightDevice.defaults(busylightDevice.defaultSettings); //set the defaults for the device

global.DEVICES.push(busylightDevice);
global.USB_DEVICES++;
}
}
catch(error) {
//probably no blink(1) detected
console.log(error);
}
}

function buildContextMenu() {
let contextMenu = Menu.buildFromTemplate([
{
Expand Down Expand Up @@ -200,6 +238,9 @@ function engageBeacon(beaconObj) {
case 'blink1':
useBlink(global.DEVICES[i], beaconObj);
break;
case 'busylight':
useBusylight(global.DEVICES[i], beaconObj);
break;
case 'screen':
useScreen(global.DEVICES[i], beaconObj);
break;
Expand All @@ -225,36 +266,23 @@ function playSound(beaconObj) {
}
}

function subscribeToNotifications() { //system events that can notify the app of a system change - perhaps like USB device being plugged in
let allowedEvents = config.get('allowedEvents');
for (let i = 0; i < allowedEvents.length; i++) {
systemPreferences.subscribeNotification(allowedEvents[i], (event, userInfo) => {
processNotification(event, userInfo);
});
}
}

function processNotification(event, info) { //process the system event
try {
if (config.get('allowedEvents').includes(event)) {
//do the stuff with the things
switch(event) {
default:
break;
}
}
}
catch(error) {
console.log(error);
}
}

function useLuxafor(luxaforDevice, beaconObj) {
//make sure beaconObj has proper color and target property
if (!beaconObj.color) {
beaconObj.color = 'red';
}

if (beaconObj.color == 'custom') {
if (beaconObj.color_r && beaconObj.color_g && beaconObj.color_b) {
//convert rgb to hex
let hex = rgbToHex(beaconObj.color_r, beaconObj.color_g, beaconObj.color_b);
beaconObj.color = hex;
}
else if (beaconObj.hex) {
beaconObj.color = beaconObj.hex;
}
}

if (!beaconObj.target) {
beaconObj.target = luxafor.targets.all;
}
Expand Down Expand Up @@ -303,17 +331,30 @@ function useLuxafor(luxaforDevice, beaconObj) {

function useBlink(blinkDevice, beaconObj) {
//make sure beaconObj has proper color and target property
let colorObj = {};

if (!beaconObj.color) {
beaconObj.color = 'red';
}

let colorObj = global.COLORS.find(color => color.id == beaconObj.color); //find the color object
if (beaconObj.color == 'custom') {
if (beaconObj.color_r && beaconObj.color_g && beaconObj.color_b) {
//convert rgb to hex
colorObj = { r: beaconObj.color_r, g: beaconObj.color_g, b: beaconObj.color_b };
}
else if (beaconObj.hex) {
colorObj = hexToRgb(beaconObj.hex);
}
}
else {
colorObj = global.COLORS.find(color => color.id == beaconObj.color); //find the color object

//if the color is not found, use the default color
if (!colorObj) {
colorObj = global.COLORS.find(color => color.id == 'red');
//if the color is not found, use the default color
if (!colorObj) {
colorObj = global.COLORS.find(color => color.id == 'red');
}
}

//invert the speed values for blink
if (beaconObj.speed) {
beaconObj.speed = 255 - beaconObj.speed;
Expand Down Expand Up @@ -362,6 +403,102 @@ function useBlink(blinkDevice, beaconObj) {
}
}

function useBusylight(busylightDevice, beaconObj) {
//make sure beaconObj has proper color and target property
let colorObj = {};

if (!beaconObj.color) {
beaconObj.color = 'red';
}

if (beaconObj.color == 'custom') {
if (beaconObj.color_r && beaconObj.color_g && beaconObj.color_b) {
//convert rgb to hex
colorObj = { r: beaconObj.color_r, g: beaconObj.color_g, b: beaconObj.color_b };
}
else if (beaconObj.hex) {
colorObj = hexToRgb(beaconObj.hex);
}
}
else {
colorObj = global.COLORS.find(color => color.id == beaconObj.color); //find the color object

//if the color is not found, use the default color
if (!colorObj) {
colorObj = global.COLORS.find(color => color.id == 'red');
}
}

try {
switch(beaconObj.beaconType) {
case 'set':
case 'fade': //couldn't really find a good way to fade this one
busylightDevice.light(colorObj.id);
break;
case 'flash':
if (!beaconObj.speed) {
beaconObj.speed = 20;
}

if (!beaconObj.repeat) {
beaconObj.repeat = 5;
}

busylightDevice.pulse([colorObj.hex], beaconObj.speed);

//use the repeat like seconds and turn it off after the rate
setTimeout(function() {
busylightDevice.off();
}, beaconObj.repeat * 1000);

break;
case 'off':
default:
busylightDevice.off();
break;
}

if (beaconObj.playSound == true && config.get('allowSounds') == true) {
//play the sound

let tone = '';
let timeoutMs = 2000;

switch(beaconObj.soundId) {
case 'single':
tone = 'TelephoneNordic';
break;
case 'triple':
tone = 'TelephoneOriginal';
break;
case 'hey':
tone = 'Quiet';
break;
case 'hey-loud':
tone = 'TelephonePickMeUp';
break;
}

busylightDevice.ring(tone);
//set a timeout to turn it off after a few seconds
setTimeout(function() {
busylightDevice.ring(false);
}, timeoutMs);
}
}
catch(error) {
//unable to write to device for some reason
console.log(error);
showNotification(
{
title: 'Beacon Error',
body: `Unable to control busylight device: ${busylightDevice.deviceId}. Did it get disconnected?`,
showNotification: true
}
)
}
}

function useScreen(screenDevice, beaconObj) {
if (config.get('allowOnScreenBeacon')) {
switch(beaconObj.beaconType) {
Expand All @@ -380,8 +517,6 @@ function useScreen(screenDevice, beaconObj) {
module.exports = {
startUp() {
setUpBeacons();

subscribeToNotifications(); //for system notifications to alert the app of changes like usb devices detected
},

showNotification(beaconObj) {
Expand Down

0 comments on commit 596bcfe

Please sign in to comment.