Enables control of Hue lights [color/luminance] via a rest API. preview code
Materials / Application:
Easy Popup with two 7x11 tarpes.
This provides a great platform for arranging your Pumpkin Patch. Attach the tarps to the side and back of the popup so that luminance levels can be controlled. You will also find the aluminum supporting structures useful for cable management and hanging props.
Polyurethane pumpkins from Michaels
Cover one side of the pumpkin with blue painters tape and draw your spooky face. The tape serves two purposes:
1) provides a platform for drawing your design one or more times.
2) exposes freshly cut areas for spray painting black; while protecting untouched orange areas.
I used an X-Acto knife to cut out my design. - “this can be dangerous, so proceed with caution at your own risk...”
Install low heat lighting. - “high heat lighting will cause a fire”. I used 3W flicker flame LED’s. It is important to get them all connected to the same power cords so you can programmatically control their ON and OFF states as they will ultimately be connected to a IOT power switch and behave accordingly to our Halloween ActorSystem.
Decorative hay bales from Michaels.
Stagger different sized hays bales for which to arrange pumpkins on.
Decorative Ivy from Michaels
Weave in and out of hay bales
Spider web looking cloth from Michaels
Hang the webs from the ceiling and sides of the Easy Popup
Three centerpiece pumpkins for projecting singing pumpkins uponProjectors
Two Android based projectors that can be programed as desired. I have 1 projector for the singing / joke telling pumpkins and another for the backdrop hologram
Something to hide your projector in
I built a box from supplies I picked up at Lowes. I left space in between side panels so the equipment inside doesn’t overheat.
Audio Detection
The ability to detect current audio levels is valuable in creating an interactive experience. Not only does this allow for the lights to have a Color / Luminance Schema that matches your music, they will also react to sounds of trick or treaters. I’ve added a bonus that blows smoke and powers the strobe light when the sum of the last 5 received audio values exceeds a certain level.
Smoke machine with a toggle switch for disbursement of smoke
Like the projector; the smoke machine requires physical interaction to have smoke blow on demand. The smoke machine must be powered on for about 5 minutes so that it can heat up enough to blow smoke when a switch is toggled. I decided to alway supply power so that it is in a constant ready state and mount a servo to the blow smoke switch. Now when the Halloween Actor System is in a automation on state smoke will blow every 30 seconds for 2 seconds
Load a program on your arduino to take commands via rest and translate them into commands to the servo
A continuation of my previous post... This introduction to a Finite State Machine DSL will show you how I am able to better manage event based transitional logic.
Lets focus on the InboundChannelActor "incoming call".
First we need to add an instance of a State Machine so that we can configure it when each inbound channel is initialized. I include a trait that allows me to have a new instance of a FiniteStateMachine, then I define the DSL which is added to the State Machine's transitions registry.
trait ChannelState implements Channel {
public FiniteStateMachine fsm = FiniteStateMachine.newInstance(None)
}
class InboundChannelActor extends BaseActor implements InboundChannelState {
public InboundChannelActor(String channelUuid, String destination) {
this.channelUuid = channelUuid
this.destination = destination
// record a transition for Event: "Parked and All" from State: "None" to State: "Greeting"
state_ChannelState__fsm.record().on([Parked, All]).from(None).to(None).act = {
log.info("on Parked from None -> None")
state_ChannelState__fsm.goToState(state_ChannelState__fsm.currentValue)
}
// record a transition for Event: "init" on a Greeting,
state_ChannelState__fsm.record().on([Init]).from(Greeting).to(Greeting).act = { event ->
// play greeting
audioActorService.actorRef.tell(new Shout(channelUuid: channelUuid, audioId: state_ChannelState__fsm.currentValue.greeting.id), context.self())
// start timer for next action
akkaService.system.scheduler().scheduleOnce(Duration.create(state_ChannelState__fsm.currentValue.nextStateSeconds, TimeUnit.SECONDS),
new Runnable() {@Override public void run() {
// go-to next state
state_ChannelState__fsm.goToState(new Init(), state_ChannelState__fsm.currentValue.nextState)
} }, akkaService.system.dispatcher())
}
// record a transition for Event: "Init" on a Menu
state_ChannelState__fsm.record().on([Init]).from(Menu).to(Menu).act = { event ->
// play menu greeting
audioActorService.actorRef.tell(new Shout(channelUuid: channelUuid, audioId: state_ChannelState__fsm.currentValue.greeting.id), akkaService.actorNoSender())
}
// record a transition for Event: "KeyPressed" on a Menu,
state_ChannelState__fsm.record().on([KeyPressed]).from(Menu).to(Menu).act = { event ->
// repeat the keys back to you...
speechActorService.actorRef.tell(new Speak(channelUuid: channelUuid, words: "dtmf ${event.digit}"), akkaService.actorNoSender())
}
// record a transition for Event: "Hungup" on All transitions...
state_ChannelState__fsm.record().on([Hungup]).from(All).to(All).act = { event ->
// stop the Actor
// todo: stop child actors
context.stop(context.self())
}
// Start the Finite State Machine with Configured Action
state_ChannelState__fsm.goToState(VoiceState.findByE164(destination))
}
}
Lastly... add the Akka onRecieve() method for firing events of to the state machine where we check the transitions registry for a match and "act"
class InboundChannelActor extends BaseActor implements InboundChannelState {
// akka's onRecieve method... fire events to the state machine for this inbound channel instance
@Override
void onReceive(Object message) throws Exception {
state_ChannelState__fsm.fire(message, state_ChannelState__fsm.currentState)
}
}
So the main idea with Actor Model is instead of using shared memory, messages are sent to actors who's state can only be altered by its self. A actor has a mailbox for receiving its messages. When a actor sends a message to a mailbox it's non-blocking. When a actor receives a message in its mailbox its uninterrupted. Actors act on their mailbox messages in order retrospectively.
Lets dive into a real world example using my PBX demonstration. A call is parked on my freeSwitch. I will send a message to a SwitchBoardActor who's job is to setup up new calls or route existing calls.
class FreeSwitchConnectionService {
switchboardActor.tell(parked, akkaService.actorNoSender())
}
My SwitchBoardActor receives the Parked() message and knows that Parked incoming messages should create a new InboundChannelActor informing it of the Parked message so the newly created InboundChannelActor can setup its' state to receive additional messages.
class SwitchBoardActor extends UntypedActor implements ActorMaker {
@Override
void onReceive(Object message) throws Exception {
if (message instanceof FreeSwitchEvent && message instanceof Parked) {
makeInboundChannelActor(message.channelUuid, message.destination).tell(message, context.self())
}
}
}
class InboundChannelActor extends BaseActor implements ObjectBinding {
@Override
void onReceive(Object message) throws Exception {
if (message instanceof Parked && !message.variableActor && message.inbound {
// tell freeSwitch to set the variableActor on the freeSwitch channel so the next message get routed to the correct instance of InboundChannelActor
freeSwitchActorService.actorRef.tell(copyObject(message, new SetVar(key: "actor", value: self.path().toString())), context.self())
}
}
}
Lets have a look at subsequent messages that have the Actor Uri attached to it. i.e: DTMF events are sent into the Actor System. We decide if we want to do text to speech or play an audio.
class FreeSwitchConnectionService {
KeyPressed keyPressed = copyMap(fsEventMap, new KeyPressed())
switchboardActor.tell(keyPressed, akkaService.actorNoSender())
}
class SwitchBoardActor extends UntypedActor implements ActorMaker {
@Override
void onReceive(Object message) throws Exception {
if (message instanceof FreeSwitchEvent && message.variableActor) {
getContext().system().actorSelection(message.variableActor).tell(message, context.self())
}
}
}
class InboundChannelActor extends BaseActor implements ObjectBinding {
def akkaService = Holders.applicationContext.getBean("akkaService")
def freeSwitchActorService = Holders.applicationContext.getBean("freeSwitchActorService")
def audioActorService = Holders.applicationContext.getBean("audioActorService")
def speechActorService = Holders.applicationContext.getBean("speechActorService")
private boolean inputDigitTimerStarted = false
private inputDigits = []
@Override
void onReceive(Object message) throws Exception {
if (message instanceof KeyPressed) {
/* put DTMF digit into an array and start a timer.
All digits in the inputDigits array will be used when timer expires.*/
inputDigits << message.digit
startInputDigitsTimer()
}
}
def startInputDigitsTimer(){
if (!inputDigitTimerStarted){
log.info( " INPUT DIGITS TIMER STARTED ")
inputDigitTimerStarted = true
akkaService.system.scheduler().scheduleOnce(Duration.create(3, TimeUnit.SECONDS),
new Runnable() {
@Override
public void run() {
def keysPressed = inputDigits.join("").toString()
inputDigits.clear()
log.info(" INPUT DIGITS ARE: $keysPressed")
if (keysPressed.length()) {
if (keysPressed == "1"){
speechActorService.actorRef.tell(new Speak(channelUuid: channelUuid, words: "Welcome" ), context.self())
} else if (keysPressed == "2") {
speechActorService.actorRef.tell(new Speak(channelUuid: channelUuid, words: "Patching you in to com systems" ), context.self())
} else {
audioActorService.actorRef.tell(new Shout(channelUuid: channelUuid, audioId: keysPressed), context.self())
}
inputDigitTimerStarted = false
}
}
}, akkaService.system.dispatcher()
)
}
}
}
So thats the gist of my actor based PBX. Download the code on GitHub for the full picture.
You can test drive this code with WebRTC
Another thing worth noting. I'm using Grails 2.4.3 in this project which includes the latest major release of groovy which implements Traits. In the code above you see my actors implement Traits. Having the ability to do multiple inheritance is a very nice feature. i.e:
* Extendable engine that can be used in any scenario.
* Typeless rules that can be added or removed at runtime. "convention over configuration"
* Decoupled decision that can ask for 1 or more rules engine results.
Design with a soldier's promotion/demotion implementation
Lets start with an interface to define the basic contract for a rules engine.
public interface IRulesEngine {
def apply(obj)
}
Here is a concrete base implementation of our rules engine. All of our business derived rules engines will extend this. Methods with the word "Rule" at the end will be executed when calling the apply() method.
class RulesEngine implements IRulesEngine {
def getRules() {
def rules = []
this.class.declaredFields.each {
def field = this."${it.name}"
if (!it.isSynthetic() && field instanceof Closure && it.name.endsWith("Rule")) {
rules << it.name
}
}
rules
}
def apply(obj) {
Set responseSet = [] as Set
rules.each { rule ->
responseSet << this."$rule"(obj)
}
responseSet
}
}
We can start off with 2 engines. Ones which return promotable and demoteable traits.
class PromotableTraitsRulesEngineService extends RulesEngine {
// example of a rule that returns many traits
def heroOnBattlefieldRule = { soldier ->
def traits = []
log.info("heroOnBattlefieldRule() ran")
War*.campaigns*.battles.collect { battle -> battle.heros in soldier}.each { battle ->
traits << """heroOnBattlefield - ${battle.campaign.war} ${battle.campaign}"""
}
return traits
}
}
class DemotableTraitsRulesEngineService extends RulesEngine {
// example of a rule that returns many traits
def insubordinationOnLeaveRule = { soldier ->
def traits = []
log.info("insubordinationOnLeaveRule() ran")
soldier.leaves.findAll{it.insubordination == true}.each { leave ->
traits << """insubordinationOnLeave - ${leave.country} ${leave.city} ${leave.place}"""
}
return traits
}
// example of a rule that returns 1 traits
def insubordinationDuringBattleRule = { soldier ->
def traits = []
log.info("insubordinationDuringBattleRule() ran")
def hasInsubordinationDuringBattleRule = War*.campaigns*.battles*.insubordinates.find { insubordinate ->
insubordinate.soldier == soldier
}
if (hasInsubordinationDuringBattleRule)
traits << "insubordinationDuringBattle"
return traits
}
}
Now we can create a service that aggregates and applies these traits.
case class Heal(item:String)
trait Healing {
val handleHealingMessages = {
case Heal(item) => println("I healed with " + item)
}
}
case class Eat(item:String)
trait Eating {
val handleEatingMessages = {
case Eat(item) => println("I ate " + item)
}
}
case class Attack(item:String)
class Soldier extends Actor with Healing with Eating {
def handleMessages = {
case Attack(item) => println("I'm attacking with my " + item)
}
def act() = {
loop {
react {
/* order matters: if more than one trait handles the same message the first one in
the orElse chain wins. I want my solder to choose "attack" over healing or eating */
handleMessages orElse handleHealingMessages orElse handleEatingMessages
}
}
}
}
val soldier = new Soldier
soldier.start
soldier ! Attack("battle riffle")
soldier ! Attack("pistol")
soldier ! Attack("knife")
soldier ! Heal("xstat sponges")
soldier ! Eat("field ration")
Have you ever seen this: "Exception Message: No value specified for parameter 1" as a result of asking a Entity for a set where its hasMany property is in a list?
def list = ['a','b','a','c','a','a','d','e','d','d','d','d','d']
JAVA
Map map = new HashMap<>();
for (T t : list) {
Integer val = map.get(t);
map.put(t, val == null ? 1 : val + 1);
}
Entry max = null;
for (Entry e : map.entrySet()) {
if (max == null || e.getValue() > max.getValue())
max = e;
}
assert 'd' == max.getKey();
The FPV live video feed to your phone uses 2.4ghz Wifi. Connected to your remote is a small range extender which connects to a camera on the Phantom 2 Vision/+. You can increase your FPV range by upgrading the antennas on your WiFi repeater and/or Vision camera. It's important to note that these upgrades can be done in several phases. Each incrementally increasing your range.
Upgrading the "pilot side" Wifi repeater
The following items are needed to perform this upgrade:
Electric Drill, Drill Press or a Dremel
U.FL Mini PCI to RP-SMA Pigtail Antenna WiFi Cable - available at amazon
LHCP 2.4 GHz antenna. I use the LHCP 2.4 GHz Half Sphere Helix 9dBi available at fpvlr.com
Industrial strength Velcro
Open the Wifi repeater by removing the 4 hex screws on the back with an alan wrench.
Make sure to carefully remove the cover or you will break the connection to the battery.
Now that you have the repeater open you should be able to find the connection for the 2 internal antennas. You can upgrade 1 or both of them.
Drill a hole in the cover of the Wifi repeater so that you can mount the RP-SMA Pigtail antenna to the extender and replace the internal antenna. You can leave the internal antenna inside of the Wifi repeater.
Reassemble the Wifi repeater. Affix velcro to the top side of the Wifi Repeter and the bottom side of your LHCP antenna and attach the antenna to the newly installed RP-SMA Pigtail.
Now your FPV should be doubled by upgrading "pilot side" internal antenna's.
Upgrading the "phantom side" Wifi
The phantom drone has 2 antennas located inside the camera which provide FVP via 2.4ghz Wifi. The Wifi repeater on your remote makes a connection to the camera via these antennas.
You will need to open up your camera with a allen wrench and replace 1 or both antennas.
Drill a hole in the back of the camera case and run a U.FL Mini PCI to RP-SMA Pigtail Antenna WiFi Cable.
There are 2 screws on either side of the lens. Loosen those a bit so that a bit of play between the main-board and antenna mounts is available.
Remove the stock antenna mini pci connection.
Attach the newly installed mini pci to rp-sma cable to the main-board.
Tighten your camera lens mount screws.
Reassemble your camera.
Now you need to mount the newly installed antenna cable to the drone. I used my dremel to shape a child safety cabinet lock into a mount and attached it into the leg of the vision.
Upgrading Complete!!!
I now enjoy between 800-1500 meters depending on my flight environment.
You might have noticed I have a pilot side remote antenna upgrade. I will update this post with the 5.8ghz remote "pilot/driver" upgrades soon...