The root cause involves three interconnected issues: widget value mapping configuration, property type compatibility handling, and service output validation. Here’s the comprehensive solution.
Widget Value Mapping:
Status light widgets use the StateFormatting property, but the binding mechanism is specific. The widget doesn’t just compare string values - it evaluates them against state definitions at render time.
First, ensure your state definitions are properly structured in the widget’s configuration panel:
- Select the status light widget
- In the StateFormatting property, use JSON format:
[
{"value": "normal", "color": "#00FF00", "displayString": "Normal"},
{"value": "warning", "color": "#FFFF00", "displayString": "Warning"},
{"value": "critical", "color": "#FF0000", "displayString": "Critical"}
]
Property Type Compatibility:
The status light widget’s Data property must receive a STRING value, but the binding needs proper type handling. Create a dedicated service for each equipment Thing:
// GetEquipmentStatus service
// Output: STRING
var currentStatus = me.status; // Direct property access
return currentStatus;
Don’t return the property object itself - return the actual string value. Property objects contain metadata that can interfere with widget value matching.
Service Output Validation:
The critical missing piece is the binding chain with proper refresh triggers. Here’s the complete mashup configuration:
-
Add a Subscription widget for the equipment Thing:
- EntityName: Your equipment Thing
- EventName: PropertyChange
- PropertyName: status
-
Add the GetEquipmentStatus service to your mashup
-
Create the binding chain:
- Subscription widget’s EventFired output → GetEquipmentStatus service’s Execute input
- GetEquipmentStatus service’s result output → Status light widget’s Data property
-
Add initialization binding:
- Mashup’s Loaded event → GetEquipmentStatus service’s Execute input
This ensures the status light updates both on initial load and whenever the property changes.
For multiple equipment items, use a more efficient pattern:
Create a GetAllEquipmentStatuses service that returns an Infotable:
var result = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
dataShapeName: "EquipmentStatusShape"
});
var equipment = Things["EquipmentGroup"].GetImplementingThings();
for (var i = 0; i < equipment.rows.length; i++) {
var thing = equipment.rows[i].name;
result.AddRow({
equipmentId: thing,
status: Things[thing].status
});
}
return result;
Bind different rows to different status lights using the Infotable Filter widget or by creating individual services that extract specific rows.
Common gotcha: If your status property is updated by a subscription (from edge devices), ensure the Thing’s property has DataChangeType set to VALUE or ALWAYS. If set to NEVER, property change events won’t fire even when the value changes.
After implementing this binding chain, the status light widgets will update immediately when threshold breaches occur and status properties change. The subscription-driven approach ensures real-time updates without polling overhead.