Overview
Industry: Facilities Management A smart office system where the AI agent acts as a facilities concierge. It checks meeting room availability, adjusts climate controls, monitors desk occupancy, and sends notifications to office displays. Commands:check_meeting_rooms— Query occupancy sensors in all meeting roomsadjust_thermostat— Set target temperature for a zonedesk_occupancy— Get desk utilization for a floorsend_notification— Display a message on an office screen
Device Client
import { DeviceClient } from '@lua-ai-global/device-client';
// Simulated office hardware
const meetingRooms = [
{ name: 'Atlas', floor: 3, capacity: 8, occupied: true, bookedUntil: '14:30' },
{ name: 'Everest', floor: 3, capacity: 12, occupied: false, bookedUntil: null },
{ name: 'Summit', floor: 4, capacity: 6, occupied: true, bookedUntil: '15:00' },
{ name: 'Pinnacle', floor: 4, capacity: 20, occupied: false, bookedUntil: null },
];
const zones: Record<string, { currentTemp: number; targetTemp: number; mode: string }> = {
'floor-3': { currentTemp: 23.2, targetTemp: 22, mode: 'cooling' },
'floor-4': { currentTemp: 21.8, targetTemp: 22, mode: 'idle' },
};
const desks: Record<string, { total: number; occupied: number }> = {
'floor-3': { total: 48, occupied: 31 },
'floor-4': { total: 52, occupied: 18 },
};
const device = new DeviceClient({
agentId: process.env.LUA_AGENT_ID!,
apiKey: process.env.LUA_API_KEY!,
deviceName: 'office-controller',
group: 'building-systems',
commands: [
{
name: 'check_meeting_rooms',
description: 'Check availability and occupancy of all meeting rooms. Returns room name, floor, capacity, and whether currently occupied.',
inputSchema: {
type: 'object',
properties: {
floor: { type: 'number', description: 'Filter by floor number (optional)' },
minCapacity: { type: 'number', description: 'Minimum room capacity (optional)' },
},
},
},
{
name: 'adjust_thermostat',
description: 'Adjust the target temperature for a building zone. Zones are identified by floor (e.g., floor-3, floor-4).',
inputSchema: {
type: 'object',
properties: {
zone: { type: 'string', description: 'Zone identifier (e.g., floor-3)' },
targetTemperature: { type: 'number', minimum: 18, maximum: 28, description: 'Target temperature in celsius' },
},
required: ['zone', 'targetTemperature'],
},
},
{
name: 'desk_occupancy',
description: 'Get desk occupancy statistics for a given floor. Returns total desks, occupied desks, and utilization percentage.',
inputSchema: {
type: 'object',
properties: {
floor: { type: 'number', description: 'Floor number to check' },
},
required: ['floor'],
},
},
{
name: 'send_notification',
description: 'Display a notification message on the office lobby or floor display screens',
inputSchema: {
type: 'object',
properties: {
message: { type: 'string', description: 'Message text to display' },
screen: { type: 'string', enum: ['lobby', 'floor-3', 'floor-4', 'all'], description: 'Target screen' },
priority: { type: 'string', enum: ['info', 'warning', 'urgent'], default: 'info' },
},
required: ['message', 'screen'],
},
},
],
});
device.onCommand('check_meeting_rooms', async (payload) => {
let rooms = meetingRooms;
if (payload?.floor) {
rooms = rooms.filter(r => r.floor === payload.floor);
}
if (payload?.minCapacity) {
rooms = rooms.filter(r => r.capacity >= payload.minCapacity);
}
return {
rooms: rooms.map(r => ({
...r,
available: !r.occupied,
})),
timestamp: new Date().toISOString(),
};
});
device.onCommand('adjust_thermostat', async (payload) => {
const zone = zones[payload.zone];
if (!zone) {
throw new Error(`Unknown zone: ${payload.zone}`);
}
zone.targetTemp = payload.targetTemperature;
zone.mode = zone.currentTemp > payload.targetTemperature ? 'cooling' : 'heating';
return {
zone: payload.zone,
currentTemperature: zone.currentTemp,
targetTemperature: zone.targetTemp,
mode: zone.mode,
};
});
device.onCommand('desk_occupancy', async (payload) => {
const floorKey = `floor-${payload.floor}`;
const floor = desks[floorKey];
if (!floor) {
throw new Error(`No data for floor ${payload.floor}`);
}
return {
floor: payload.floor,
totalDesks: floor.total,
occupiedDesks: floor.occupied,
availableDesks: floor.total - floor.occupied,
utilization: Math.round((floor.occupied / floor.total) * 100),
};
});
device.onCommand('send_notification', async (payload) => {
console.log(`[DISPLAY ${payload.screen}] ${payload.priority?.toUpperCase() || 'INFO'}: ${payload.message}`);
return {
sent: true,
screen: payload.screen,
message: payload.message,
timestamp: new Date().toISOString(),
};
});
async function main() {
await device.connect();
console.log('Office controller online');
}
main().catch(console.error);
import asyncio
import os
from datetime import datetime, timezone
from lua_device import DeviceClient, DeviceCommandDefinition
# Simulated office hardware
meeting_rooms = [
{"name": "Atlas", "floor": 3, "capacity": 8, "occupied": True, "bookedUntil": "14:30"},
{"name": "Everest", "floor": 3, "capacity": 12, "occupied": False, "bookedUntil": None},
{"name": "Summit", "floor": 4, "capacity": 6, "occupied": True, "bookedUntil": "15:00"},
{"name": "Pinnacle", "floor": 4, "capacity": 20, "occupied": False, "bookedUntil": None},
]
zones = {
"floor-3": {"currentTemp": 23.2, "targetTemp": 22, "mode": "cooling"},
"floor-4": {"currentTemp": 21.8, "targetTemp": 22, "mode": "idle"},
}
desks = {
"floor-3": {"total": 48, "occupied": 31},
"floor-4": {"total": 52, "occupied": 18},
}
client = DeviceClient(
agent_id=os.environ["LUA_AGENT_ID"],
api_key=os.environ["LUA_API_KEY"],
device_name="office-controller",
group="building-systems",
commands=[
DeviceCommandDefinition(
name="check_meeting_rooms",
description="Check availability and occupancy of all meeting rooms. Returns room name, floor, capacity, and whether currently occupied.",
input_schema={
"type": "object",
"properties": {
"floor": {"type": "number", "description": "Filter by floor number (optional)"},
"minCapacity": {"type": "number", "description": "Minimum room capacity (optional)"},
},
},
),
DeviceCommandDefinition(
name="adjust_thermostat",
description="Adjust the target temperature for a building zone. Zones are identified by floor (e.g., floor-3, floor-4).",
input_schema={
"type": "object",
"properties": {
"zone": {"type": "string", "description": "Zone identifier (e.g., floor-3)"},
"targetTemperature": {"type": "number", "minimum": 18, "maximum": 28, "description": "Target temperature in celsius"},
},
"required": ["zone", "targetTemperature"],
},
),
DeviceCommandDefinition(
name="desk_occupancy",
description="Get desk occupancy statistics for a given floor. Returns total desks, occupied desks, and utilization percentage.",
input_schema={
"type": "object",
"properties": {
"floor": {"type": "number", "description": "Floor number to check"},
},
"required": ["floor"],
},
),
DeviceCommandDefinition(
name="send_notification",
description="Display a notification message on the office lobby or floor display screens",
input_schema={
"type": "object",
"properties": {
"message": {"type": "string", "description": "Message text to display"},
"screen": {"type": "string", "enum": ["lobby", "floor-3", "floor-4", "all"], "description": "Target screen"},
"priority": {"type": "string", "enum": ["info", "warning", "urgent"], "default": "info"},
},
"required": ["message", "screen"],
},
),
],
)
@client.on_command("check_meeting_rooms")
async def handle_check_meeting_rooms(payload):
rooms = meeting_rooms
if payload and payload.get("floor"):
rooms = [r for r in rooms if r["floor"] == payload["floor"]]
if payload and payload.get("minCapacity"):
rooms = [r for r in rooms if r["capacity"] >= payload["minCapacity"]]
return {
"rooms": [{**r, "available": not r["occupied"]} for r in rooms],
"timestamp": datetime.now(timezone.utc).isoformat(),
}
@client.on_command("adjust_thermostat")
async def handle_adjust_thermostat(payload):
zone = zones.get(payload["zone"])
if not zone:
raise Exception(f"Unknown zone: {payload['zone']}")
zone["targetTemp"] = payload["targetTemperature"]
zone["mode"] = "cooling" if zone["currentTemp"] > payload["targetTemperature"] else "heating"
return {
"zone": payload["zone"],
"currentTemperature": zone["currentTemp"],
"targetTemperature": zone["targetTemp"],
"mode": zone["mode"],
}
@client.on_command("desk_occupancy")
async def handle_desk_occupancy(payload):
floor_key = f"floor-{payload['floor']}"
floor = desks.get(floor_key)
if not floor:
raise Exception(f"No data for floor {payload['floor']}")
return {
"floor": payload["floor"],
"totalDesks": floor["total"],
"occupiedDesks": floor["occupied"],
"availableDesks": floor["total"] - floor["occupied"],
"utilization": round((floor["occupied"] / floor["total"]) * 100),
}
@client.on_command("send_notification")
async def handle_send_notification(payload):
priority = (payload.get("priority") or "info").upper()
print(f"[DISPLAY {payload['screen']}] {priority}: {payload['message']}")
return {
"sent": True,
"screen": payload["screen"],
"message": payload["message"],
"timestamp": datetime.now(timezone.utc).isoformat(),
}
async def main():
await client.connect()
print("Office controller online")
asyncio.run(main())
Agent Configuration
// src/index.ts
import { LuaAgent, LuaSkill } from 'lua-cli';
const facilitiesSkill = new LuaSkill({
name: 'facilities-concierge',
description: 'Smart office management',
context: `
You manage office facilities through connected devices.
Device tools:
- check_meeting_rooms: Use when someone needs a meeting room. Filter by floor or capacity.
- adjust_thermostat: Use when someone reports temperature issues. Range: 18-28C.
- desk_occupancy: Use to report floor utilization.
- send_notification: Use to broadcast messages to office screens.
Guidelines:
- When someone needs a room, check availability and suggest the best match
- For temperature complaints, check current temp first, then adjust
- Only send urgent notifications for actual emergencies
- Be friendly and helpful -- you are the office concierge
`,
tools: [],
});
export const agent = new LuaAgent({
name: 'office-concierge',
persona: `You are a friendly office concierge. You help employees find meeting rooms,
manage comfort settings, and stay informed about office status. Be warm and helpful.`,
skills: [facilitiesSkill],
});
Next Steps
Warehouse Scanner
Logistics and inventory management
Industrial Sensor
Factory monitoring on Pico W
Retail Kiosk
Customer-facing kiosk with NFC and receipts
Self-Describing Commands
How to write effective command definitions

