/**
*
* @author greg (at) myrobotlab.org
*
* This file is part of MyRobotLab (http://myrobotlab.org).
*
* MyRobotLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* MyRobotLab is distributed in the hope that it will be useful or fun,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* All libraries in thirdParty bundle are subject to their own license
* requirements - please refer to http://myrobotlab.org/libraries for
* details.
*
* Enjoy !
*
* */
package org.myrobotlab.service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.myrobotlab.framework.Service;
import org.myrobotlab.framework.ServiceType;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.myrobotlab.service.interfaces.DeviceControl;
import org.myrobotlab.service.interfaces.DeviceController;
import org.myrobotlab.service.interfaces.NeoPixelControl;
import org.myrobotlab.service.interfaces.NeoPixelController;
import org.myrobotlab.service.interfaces.ServiceInterface;
import org.slf4j.Logger;
public class NeoPixel extends Service implements NeoPixelControl {
private static final long serialVersionUID = 1L;
public final static Logger log = LoggerFactory.getLogger(NeoPixel.class);
transient NeoPixelController controller;
public static class PixelColor {
public int address;
public int red;
public int blue;
public int green;
public boolean changed;
PixelColor(int address, int red, int green, int blue) {
this.address = address;
this.red = red;
this.blue = blue;
this.green = green;
changed=true;
}
PixelColor() {
address = 0;
red = 0;
blue = 0;
green = 0;
changed=true;
}
public boolean isEqual(PixelColor pix){
if(pix.red==red && pix.green==green && pix.blue==blue){
return true;
}
return false;
}
}
public HashMap<Integer, PixelColor> pixelMatrix = new HashMap<Integer, PixelColor>();
public List<PixelColor> savedPixelMatrix = new ArrayList<PixelColor>();
public Integer numPixel = 0;
/**
* list of names of possible controllers
*/
public List<String> controllers;
public String controllerName;
boolean isAttached=false;
public Integer pin;
public boolean off = false;
public static transient final int NEOPIXEL_ANIMATION_NO_ANIMATION = 0;
public static transient final int NEOPIXEL_ANIMATION_STOP = 1;
public static transient final int NEOPIXEL_ANIMATION_COLOR_WIPE = 2;
public static transient final int NEOPIXEL_ANIMATION_LARSON_SCANNER = 3;
public static transient final int NEOPIXEL_ANIMATION_THEATER_CHASE = 4;
public static transient final int NEOPIXEL_ANIMATION_THEATER_CHASE_RAINBOW = 5;
public static transient final int NEOPIXEL_ANIMATION_RAINBOW = 6;
public static transient final int NEOPIXEL_ANIMATION_RAINBOW_CYCLE = 7;
public static transient final int NEOPIXEL_ANIMATION_FLASH_RANDOM = 8;
public static transient final int NEOPIXEL_ANIMATION_IRONMAN = 9;
public List<String> animations = Arrays.asList("No animation","Stop","Color Wipe","Larson Scanner","Theater Chase","Theater Chase Rainbow","Rainbow","Rainbow Cycle","Flash Random","Ironman");
public transient String animation ="No animation";
public transient boolean[] animationSetting = {false,false}; // red, green, blue, speed
public transient boolean animationSettingColor = false;
public transient boolean animationSettingSpeed = false;
transient HashMap<Integer, boolean[]> animationSettings = new HashMap<Integer, boolean[]>();
public NeoPixel(String n) {
super(n);
animationSettings.put(NEOPIXEL_ANIMATION_STOP, new boolean[]{false,false});
animationSettings.put(NEOPIXEL_ANIMATION_COLOR_WIPE, new boolean[]{true,true});
animationSettings.put(NEOPIXEL_ANIMATION_LARSON_SCANNER, new boolean[]{true,true});
animationSettings.put(NEOPIXEL_ANIMATION_THEATER_CHASE, new boolean[]{true,true});
animationSettings.put(NEOPIXEL_ANIMATION_THEATER_CHASE_RAINBOW, new boolean[]{false,true});
animationSettings.put(NEOPIXEL_ANIMATION_RAINBOW, new boolean[]{false,true});
animationSettings.put(NEOPIXEL_ANIMATION_RAINBOW_CYCLE, new boolean[]{false,true});
animationSettings.put(NEOPIXEL_ANIMATION_FLASH_RANDOM, new boolean[]{true,true});
animationSettings.put(NEOPIXEL_ANIMATION_IRONMAN, new boolean[]{true,true});
subscribe(Runtime.getInstance().getName(), "registered", this.getName(), "onRegistered");
}
public void onRegistered(ServiceInterface s) {
refreshControllers();
broadcastState();
}
public List<String> refreshControllers() {
controllers = Runtime.getServiceNamesFromInterface(NeoPixelController.class);
return controllers;
}
@Override
public NeoPixelController getController() {
return controller;
}
public String getControllerName() {
String controlerName = null;
if (controller != null) {
controlerName = controller.getName();
}
return controlerName;
}
public boolean isAttached() {
if(controller != null){
if(((Arduino) controller).getDeviceId((DeviceControl)this)!=null) {
isAttached=true;
return true;
}
controller = null;
}
isAttached = false;
return false;
}
public void setPixel(int address, int red, int green, int blue) {
PixelColor pixel = new PixelColor(address, red, green, blue);
setPixel(pixel);
}
public void setPixel(String address, String red, String green, String blue) {
PixelColor pixel = new PixelColor(Integer.parseInt(address), Integer.parseInt(red), Integer.parseInt(green), Integer.parseInt(blue));
setPixel(pixel);
}
public void setPixel(PixelColor pixel) {
if (off)
return;
if (pixel.address <= getNumPixel()) {
PixelColor pix=pixelMatrix.get(pixel.address);
if(pix!=null && !pix.isEqual(pixel)){
pixel.changed = true;
}
else{
pixel.changed = false;
}
pixelMatrix.put(pixel.address, pixel);
} else {
log.info("Pixel address over the number of pixel");
}
}
public void sendPixel(PixelColor pixel) {
if (off)
return;
List<Integer> msg = new ArrayList<Integer>();
msg.add(pixel.address);
msg.add(pixel.red);
msg.add(pixel.green);
msg.add(pixel.blue);
setPixel(pixel);
controller.neoPixelWriteMatrix(this, msg);
//savedPixelMatrix.clear();
//savedPixelMatrix.add(pixel);
}
public void sendPixel(int address, int red, int green, int blue) {
PixelColor pixel = new PixelColor(address, red, green, blue);
sendPixel(pixel);
}
public void sendPixel(String address, String red, String green, String blue) {
PixelColor pixel = new PixelColor(Integer.parseInt(address), Integer.parseInt(red), Integer.parseInt(green), Integer.parseInt(blue));
sendPixel(pixel);
}
public void writeMatrix() {
savedPixelMatrix.clear();
Set<Entry<Integer, PixelColor>> set = pixelMatrix.entrySet();
Iterator<Entry<Integer, PixelColor>> i = set.iterator();
List<Integer> msg = new ArrayList<Integer>();
while (i.hasNext()) {
Map.Entry<Integer, PixelColor> me = (Map.Entry<Integer, PixelColor>) i.next();
PixelColor pix=me.getValue();
//will only send if the pixel value have changed
if(pix.changed){
msg.add(pix.address);
msg.add(pix.red);
msg.add(pix.green);
msg.add(pix.blue);
pix.changed=false;
me.setValue(pix);
}
savedPixelMatrix.add(me.getValue());
if (msg.size() > 32) {
if (!off && isAttached())
controller.neoPixelWriteMatrix(this, msg);
msg.clear();
}
}
if (!off && isAttached())
controller.neoPixelWriteMatrix(this, msg);
broadcastState();
}
public Integer getPin() {
return pin;
}
public int getNumPixel() {
return numPixel;
}
public void turnOff() {
for (int i = 1; i <= numPixel; i++) {
PixelColor pixel = new PixelColor(i, 0, 0, 0);
setPixel(pixel);
}
animationStop();
writeMatrix();
off = true;
}
public void turnOn() {
off = false;
broadcastState();
}
/**
* This static method returns all the details of the class without it having
* to be constructed. It has description, categories, dependencies, and peer
* definitions.
*
* @return ServiceType - returns all the data
*
*/
static public ServiceType getMetaData() {
ServiceType meta = new ServiceType(NeoPixel.class.getCanonicalName());
meta.addDescription("Control a Neopixel hardware");
meta.setAvailable(true); // false if you do not want it viewable in a
// gui
// add dependency if necessary
// meta.addDependency("org.coolproject", "1.0.0");
meta.addCategory("Neopixel, Control");
return meta;
}
public void attach(String controllerName, int pin, int numPixel) throws Exception {
attach((NeoPixelController) Runtime.getService(controllerName),pin,numPixel);
}
public void attach(String controllerName, String pin, String numPixel) throws Exception {
attach((NeoPixelController) Runtime.getService(controllerName),Integer.parseInt(pin),Integer.parseInt(numPixel));
}
@Override
public void attach(NeoPixelController controller, int pin, int numPixel) throws Exception {
subscribe(controller.getName(), "publishAttachedDevice");
this.pin = pin;
this.numPixel = numPixel;
// clear the old matrix
pixelMatrix.clear();
// create a new matrix
for (int i = 1; i < numPixel + 1; i++) {
setPixel(new PixelColor(i, 0, 0, 0));
}
//setController(controller);
controller.deviceAttach(this, pin, numPixel);
int count = 0;
while(!isAttached){
count++;
sleep(100);
if (count > 4) break;
}
broadcastState();
}
public void onAttachedDevice(String deviceName){
if (deviceName.equals(this.getName())){
isAttached = true;
broadcastState();
}
}
@Override
public void setController(DeviceController controller) {
if (controller == null) {
error("setting null as controller");
return;
}
log.info(String.format("%s setController %s", getName(), controller.getName()));
this.controller = (NeoPixelController) controller;
controllerName = this.controller.getName();
}
public void detach(){
detach(controller);
}
@Override
public void detach(NeoPixelController controller) {
// let the controller you want to detach this device
controller.deviceDetach(this);
// setting controller reference to null
this.controller = null;
isAttached = false;
refreshControllers();
broadcastState();
}
public void refresh(){
broadcastState();
}
public static void main(String[] args) throws InterruptedException {
LoggingFactory.init(Level.INFO);
try {
WebGui webgui = (WebGui) Runtime.create("webgui", "WebGui");
// webgui.autoStartBrowser(false);
webgui.startService();
Runtime.start("gui", "GUIService");
Runtime.start("python", "Python");
Arduino arduino = (Arduino) Runtime.start("arduino", "Arduino");
arduino.arduinoPath="C:\\Program Files (x86)\\Arduino";
arduino.setBoardMega();
arduino.connect("COM15");
// Arduino arduino1 = (Arduino) Runtime.start("arduino1", "Arduino");
// arduino1.setBoardUno();
// arduino1.connect(arduino, "Serial1");
// //arduino.setDebug(true);
NeoPixel neopixel = (NeoPixel) Runtime.start("neopixel", "NeoPixel");
// webgui.startBrowser("http://localhost:8888/#/service/neopixel");
neopixel.attach(arduino, 29, 16);
//sleep(50);
PixelColor pix = new NeoPixel.PixelColor(1, 255, 255, 0);
neopixel.setPixel(pix);
neopixel.setAnimation(NEOPIXEL_ANIMATION_IRONMAN, 255, 0, 0, 1);
//arduino.setLoadTimingEnabled(true);
Servo servo=(Servo)Runtime.start("servo","Servo");
servo.attach(arduino, 5);
servo.moveTo(180);
} catch (Exception e) {
Logging.logError(e);
}
}
@Override
public void setAnimation(int animation, int red, int green, int blue, int speed) {
//protect against 0 and negative speed
if (speed < 1) speed = 1;
controller.neoPixelSetAnimation(this, animation, red, green, blue, speed);
this.animation = animationIntToString(animation);
broadcastState();
}
String animationIntToString( int animation) {
switch(animation) {
case NEOPIXEL_ANIMATION_NO_ANIMATION:
return "No animation";
case NEOPIXEL_ANIMATION_STOP:
return "Stop";
case NEOPIXEL_ANIMATION_COLOR_WIPE:
return "Color Wipe";
case NEOPIXEL_ANIMATION_LARSON_SCANNER:
return "Larson Scanner";
case NEOPIXEL_ANIMATION_THEATER_CHASE:
return "Theater Chase";
case NEOPIXEL_ANIMATION_THEATER_CHASE_RAINBOW:
return "Theater Chase Rainbow";
case NEOPIXEL_ANIMATION_RAINBOW:
return "Rainbow";
case NEOPIXEL_ANIMATION_RAINBOW_CYCLE:
return "Rainbow Cycle";
case NEOPIXEL_ANIMATION_FLASH_RANDOM:
return "Flash Random";
case NEOPIXEL_ANIMATION_IRONMAN:
return "Ironman";
default:
log.error("Unknow Animation type {}", animation);
return "No Animation";
}
}
@Override
public void setAnimation(String animation, int red, int green, int blue, int speed) {
setAnimation(animationStringToInt(animation), red, green, blue, speed);
}
@Override
public void setAnimation(String animation, String red, String green, String blue, String speed) {
setAnimation(animationStringToInt(animation), Integer.parseInt(red), Integer.parseInt(green), Integer.parseInt(blue), Integer.parseInt(speed));
}
int animationStringToInt(String animation) {
switch(animation) {
case "No animation":
return NEOPIXEL_ANIMATION_STOP;
case "Stop":
return NEOPIXEL_ANIMATION_STOP;
case "Color Wipe":
return NEOPIXEL_ANIMATION_COLOR_WIPE;
case "Larson Scanner":
return NEOPIXEL_ANIMATION_LARSON_SCANNER;
case "Theater Chase":
return NEOPIXEL_ANIMATION_THEATER_CHASE;
case "Theater Chase Rainbow":
return NEOPIXEL_ANIMATION_THEATER_CHASE_RAINBOW;
case "Rainbow":
return NEOPIXEL_ANIMATION_RAINBOW;
case "Rainbow Cycle":
return NEOPIXEL_ANIMATION_RAINBOW_CYCLE;
case "Flash Random":
return NEOPIXEL_ANIMATION_FLASH_RANDOM;
case "Ironman":
return NEOPIXEL_ANIMATION_IRONMAN;
default:
log.error("Unknow Animation type {}", animation);
return NEOPIXEL_ANIMATION_STOP;
}
}
@Override
public void setAnimationSetting(String animation) {
// TODO Auto-generated method stub
animationSetting = animationSettings.get(animationStringToInt(animation));
animationSettingColor = animationSetting[0];
animationSettingSpeed = animationSetting[1];
broadcastState();
}
public void animationStop() {
setAnimation(NEOPIXEL_ANIMATION_STOP,0,0,0,0);
}
}