Skip to main content

Overview

Industry: Manufacturing A factory floor monitoring system running on a Raspberry Pi Pico W. The device reads vibration and temperature sensors, provides an emergency stop command, and fires triggers when anomalies are detected. Commands:
  • read_vibration — Read vibration amplitude from an accelerometer
  • read_temperature — Read bearing temperature
  • emergency_stop — Trigger the emergency stop relay
Triggers:
  • vibration_anomaly — Fires when vibration exceeds safe threshold

Device Client (MicroPython)

import network
import machine
import time

# -- WiFi --
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("FACTORY_WIFI", "secure_password_here")

while not wlan.isconnected():
    time.sleep(0.5)

print("WiFi connected:", wlan.ifconfig()[0])

# -- Hardware setup --
# Onboard LED for status indication
status_led = machine.Pin("LED", machine.Pin.OUT)

# ADC for vibration sensor (analog accelerometer on GP26)
vibration_adc = machine.ADC(machine.Pin(26))

# DS18B20 or analog temp sensor on GP27
temp_adc = machine.ADC(machine.Pin(27))

# Emergency stop relay on GP16
estop_relay = machine.Pin(16, machine.Pin.OUT, value=0)

# -- Device --
from lua_device import LuaDevice

device = LuaDevice(
    agent_id="your-agent-id",
    api_key="your-api-key",
    device_name="cnc-monitor-01",
    server="mqtt.heylua.ai",
    group="factory-floor",
)

@device.command("read_vibration")
def read_vibration(payload):
    # Read ADC value and convert to g-force (simplified)
    raw = vibration_adc.read_u16()
    amplitude_g = (raw / 65535.0) * 4.0  # 0-4g range
    return {
        "amplitude_g": round(amplitude_g, 3),
        "raw_adc": raw,
        "status": "warning" if amplitude_g > 2.5 else "normal",
    }

@device.command("read_temperature")
def read_temperature(payload):
    raw = temp_adc.read_u16()
    # Convert to celsius (simplified linear conversion)
    temp_c = (raw / 65535.0) * 150.0  # 0-150C range for bearing temp
    return {
        "temperature": round(temp_c, 1),
        "unit": "celsius",
        "status": "critical" if temp_c > 80 else "warning" if temp_c > 60 else "normal",
    }

@device.command("emergency_stop")
def emergency_stop(payload):
    estop_relay.on()  # Activate relay (normally open -> closed)
    status_led.on()   # Visual indicator

    reason = payload.get("reason", "manual trigger")
    print("[ESTOP] Emergency stop activated:", reason)

    return {
        "activated": True,
        "reason": reason,
        "timestamp": str(time.time()),
    }

# -- Connect and run --
device.connect()
status_led.on()  # LED on = connected
print("Factory monitor online")

# -- Main loop with anomaly detection --
VIBRATION_THRESHOLD = 3.0  # g-force
last_check = time.time()
check_interval = 10  # seconds

while True:
    try:
        device._client.check_msg()

        now = time.time()

        # Heartbeat
        if now - device._last_heartbeat >= device._heartbeat_interval:
            device._client.publish(device._topic_prefix + "heartbeat", b"", qos=0)
            device._last_heartbeat = now

        # Periodic vibration check
        if now - last_check >= check_interval:
            raw = vibration_adc.read_u16()
            amplitude = (raw / 65535.0) * 4.0

            if amplitude > VIBRATION_THRESHOLD:
                device.trigger("vibration_anomaly", {
                    "amplitude_g": round(amplitude, 3),
                    "threshold_g": VIBRATION_THRESHOLD,
                    "machine": "CNC-Mill-04",
                    "location": "bay-3",
                })
                # Blink LED rapidly to indicate alert
                for _ in range(5):
                    status_led.toggle()
                    time.sleep_ms(100)
                status_led.on()

            last_check = now

        # Clean dedup cache
        if len(device._seen_ids) > 100:
            device._clean_dedup()

        time.sleep_ms(100)

    except OSError as e:
        print("Connection lost:", e)
        status_led.off()
        device._reconnect()
        status_led.on()
    except Exception as e:
        print("Error:", e)
        time.sleep(1)

Agent-Side Trigger Handler

// src/triggers/vibration-anomaly.ts
import { defineDeviceTrigger } from 'lua-cli';
import { z } from 'zod';

export const vibrationAnomaly = defineDeviceTrigger({
  name: 'vibration-anomaly',
  description: 'Fired when a factory machine vibration reading exceeds the safe threshold',
  payloadSchema: z.object({
    amplitude_g: z.number(),
    threshold_g: z.number(),
    machine: z.string(),
    location: z.string(),
  }),
  execute: async (payload, { agent, device }) => {
    const severity = payload.amplitude_g > payload.threshold_g * 1.5 ? 'CRITICAL' : 'WARNING';

    await agent.chat(
      `${severity} VIBRATION ALERT from ${device.name}: ` +
      `Machine "${payload.machine}" in ${payload.location} ` +
      `reading ${payload.amplitude_g}g (threshold: ${payload.threshold_g}g). ` +
      (severity === 'CRITICAL'
        ? 'This is significantly above threshold. Consider activating emergency stop.'
        : 'Monitor closely and schedule maintenance if readings persist.')
    );
  },
});

Agent Configuration

// src/index.ts
import { LuaAgent, LuaSkill } from 'lua-cli';
import { vibrationAnomaly } from './triggers/vibration-anomaly';

const factorySkill = new LuaSkill({
  name: 'factory-monitoring',
  description: 'Industrial equipment monitoring and control',
  context: `
    You monitor factory equipment through connected sensors.

    Device tools:
    - read_vibration: Check machine vibration levels. Normal < 2.5g, warning < 3.0g, critical > 3.0g.
    - read_temperature: Check bearing temperature. Normal < 60C, warning < 80C, critical > 80C.
    - emergency_stop: CRITICAL COMMAND. Only use when explicitly requested or when readings indicate
      imminent equipment failure. Always confirm with the operator first unless automated shutdown
      is triggered.

    When receiving vibration anomaly triggers:
    1. Read the current vibration and temperature
    2. Assess combined risk
    3. Recommend maintenance or emergency stop based on severity
  `,
  tools: [],
});

export const agent = new LuaAgent({
  name: 'factory-monitor',
  persona: `You are a factory floor monitoring assistant. You help operators keep equipment
    running safely. Be precise with readings. Escalate critical situations immediately.
    Never hesitate to recommend an emergency stop if readings indicate danger.`,
  skills: [factorySkill],
  deviceTriggers: [vibrationAnomaly],
});

Next Steps

Pico W Setup

Step-by-step hardware setup guide

MicroPython Client

Full MicroPython client reference

Warehouse Scanner

Node.js logistics example

Triggers

How triggers flow from device to agent