package context.apps.demos.roomlight;
import context.arch.discoverer.ComponentDescription;
import context.arch.discoverer.component.NonConstantAttributeElement;
import context.arch.discoverer.query.AbstractQueryItem;
import context.arch.discoverer.query.ElseQueryItem;
import context.arch.discoverer.query.ORQueryItem;
import context.arch.discoverer.query.RuleQueryItem;
import context.arch.discoverer.query.comparison.AttributeComparison;
import context.arch.enactor.Enactor;
import context.arch.enactor.EnactorReference;
import context.arch.service.helper.ServiceInput;
import context.arch.storage.AttributeNameValue;
import context.arch.storage.Attributes;
import context.arch.widget.Widget;
import context.arch.widget.Widget.WidgetData;
public class RoomEnactor extends Enactor {
public static final short BRIGHTNESS_THRESHOLD = 100;
@SuppressWarnings("serial")
public RoomEnactor(AbstractQueryItem<?,?> inWidgetQuery, AbstractQueryItem<?,?> outWidgetQuery) {
super(inWidgetQuery, outWidgetQuery, "light", "");
/*
* Set up for enactor references, one for each outcome
*/
// light off
AbstractQueryItem<?, ?> offQI =
new ORQueryItem(
RuleQueryItem.instance(
new NonConstantAttributeElement(AttributeNameValue.instance("presence", 0))), // equal to 0; no one in the room, OR
RuleQueryItem.instance(
new NonConstantAttributeElement(AttributeNameValue.instance("brightness", BRIGHTNESS_THRESHOLD)),
new AttributeComparison(AttributeComparison.Comparison.GREATER)) // brightness more than BRIGHTNESS_THRESHOLD
);
EnactorReference er = new RoomEnactorReference(
offQI,
LightWidget.LIGHT_OFF);
er.addServiceInput(new ServiceInput("LightService", "lightOff"));
addReference(er);
// light on, and brightness dependent
er = new RoomEnactorReference(
new ElseQueryItem(offQI),
LightWidget.LIGHT_ON);
er.addServiceInput(new ServiceInput("LightService", "lightOn",
new Attributes() {{
addAttribute("light", Integer.class);
}}));
addReference(er);
start();
}
private int light;
public int getLight() {
return light;
}
private class RoomEnactorReference extends EnactorReference {
public RoomEnactorReference(AbstractQueryItem<?,?> conditionQuery, String outcomeValue) {
super(RoomEnactor.this, conditionQuery, outcomeValue);
}
private double LIGHT_SCALE = Math.pow(BRIGHTNESS_THRESHOLD, 0.33);
@Override
protected Attributes conditionSatisfied(ComponentDescription inWidgetState, Attributes outAtts) {
long timestamp = outAtts.getAttributeValue(Widget.TIMESTAMP);
WidgetData data = new WidgetData("LightWidget", timestamp);
if (outcomeValue == LightWidget.LIGHT_ON) {
/*
* "Proprietary or complicated" way to calculate light voltage level from sensed brightness
* Actually, using Steven's power law (http://en.wikipedia.org/wiki/Steven%27s_power_law) for light perception
* psi = k*I^0.33
* Scaled to 10
*/
short brightness = inWidgetState.getAttributeValue(RoomWidget.BRIGHTNESS);
light = (int)(10*Math.pow(BRIGHTNESS_THRESHOLD - brightness, 0.33) / LIGHT_SCALE); // brightness will never be lower than BRIGHTNESS_THRESHOLD
}
else {
light = 0;
}
/*
* Note that outcomeValue would not equal the light level, so user may not be able to ask about specific level
* TODO consider whether and how to support functional relationships
*/
data.setAttributeValue(LightWidget.LIGHT, light);
outAtts.putAll(data.toAttributes());
return outAtts;
}
}
}