by skunxicat

Alexa, what’s my WiFi password?

The full ql48 evolution story

It Started with a Router

Problem: My router didn’t have an API. I wanted to check WAN status, reboot remotely, get device lists.

Solution: Scrape the web interface, wrap it in shell functions, deploy as Lambda.

# router-api/src/handler.sh
wan_status() {
    local session=$(router_login)
    curl -s "http://192.168.1.1/wan.cgi" \
        -H "Cookie: SESSION=$session" \
        | parse_wan_data
}

Result: REST API for router control. Simple, functional, done.

The First Network Effect

Observation: If I can control my router via API, I can integrate it with other systems.

Next step: Alexa skill.

# alexa-skill/src/handler.sh  
alexa_handler() {
    local intent=$(echo "$1" | jq -r '.request.intent.name')
    case $intent in
        "GetWifiPassword")
            get_wifi_credentials
            ;;
        "RebootRouter") 
            reboot_router
            ;;
    esac
}

Result: “Alexa, what’s my WiFi password?” works.

The IoT Expansion

Realization: If I can make my router programmable, what about other devices?

Next target: LED strips for visual notifications.

# ql48-controller/src/handler.sh
github_webhook() {
    local event_type=$(echo "$1" | jq -r '.action')
    case $event_type in
        "opened")
            mqtt_publish "ql48/leds/all" '{"effect": "pulse", "color": "blue"}'
            ;;
        "merged")
            mqtt_publish "ql48/leds/all" '{"effect": "rainbow", "duration": 5}'
            ;;
    esac
}

Result: LED strips react to GitHub events, deployments, alerts.

The Platform Emergence

Pattern recognition: Every integration followed the same structure:

  1. Receive event (webhook, API call, schedule)
  2. Process with shell logic
  3. Trigger action (MQTT, HTTP, AWS API)

Abstraction: Event-driven interfaces for the physical world.

# ql48-platform/core/event-router.sh
route_event() {
    local source="$1"
    local event="$2"
    
    case $source in
        "github")
            handle_github_event "$event"
            ;;
        "router")
            handle_router_event "$event"
            ;;
        "cloudwatch")
            handle_aws_event "$event"
            ;;
    esac
}

The Architecture Evolution

Phase 1: Single Function

GitHub → Lambda → Router API

Phase 2: Multi-Device

GitHub → Lambda → MQTT Broker → LED Controller
Router → Lambda → Alexa Response

Phase 3: Event Platform

Multiple Sources → Event Router → Multiple Targets
    ↓                    ↓              ↓
  GitHub            Shell Logic      MQTT
  Router              jq/curl        HTTP
  CloudWatch         AWS CLI        Alexa
  Webhooks                         Router

The Technical Stack

Infrastructure: All cloudless modules

  • terraform-aws-lambda-runtime for custom shell runtime
  • terraform-aws-rest-api for webhook endpoints
  • terraform-aws-website for status dashboards

Runtime: lambda-shell-runtime:micro

  • jq for JSON processing
  • curl for HTTP calls
  • awscurl for AWS API access

Communication: MQTT + HTTP

  • AWS IoT Core for cloud messaging
  • Local Mosquitto bridge for device communication
  • HTTP webhooks for external integrations

The Business Logic

# The entire platform logic
process_event() {
    local source="$1"
    local payload="$2"
    
    # Parse event
    local event_type=$(echo "$payload" | jq -r '.type')
    local event_data=$(echo "$payload" | jq -r '.data')
    
    # Route to handlers
    case "$source:$event_type" in
        "github:push")
            led_notification "deployment" "blue"
            ;;
        "router:device_connected")
            alexa_announce "New device connected"
            ;;
        "cloudwatch:alarm")
            led_alert "critical" "red"
            router_reboot_if_needed
            ;;
    esac
}

That’s it. The entire platform is shell functions processing JSON.

The Unexpected Benefits

Debugging Simplicity

Every component is inspectable:

# Test any part locally
echo '{"type": "push", "repo": "test"}' | github_handler

Cost Efficiency

  • Router API: $0.02/month
  • LED Controller: $0.05/month
  • Alexa Skill: $0.01/month
  • Total: Under $0.10/month for the entire platform

Reliability

Shell scripts don’t have dependency conflicts, memory leaks, or framework updates breaking things.

Extensibility

Adding new integrations is trivial:

# New handler in 5 minutes
slack_handler() {
    local message="$1"
    curl -X POST "$SLACK_WEBHOOK" \
        -d '{"text": "'"$message"'"}'
}

The Platform Today

Active integrations:

  • GitHub webhooks → LED notifications
  • Router status → Alexa announcements
  • CloudWatch alarms → Visual alerts
  • Manual controls → Voice commands
  • Website traffic → Ambient lighting

Infrastructure cost: <$1/month Maintenance time: ~1 hour/month Reliability: 99.9% uptime

The Lessons

1. Simple Decisions Compound

Router API → Alexa skill → IoT platform. Each step was obvious, but the combination created something bigger.

2. Shell Scripts Scale Surprisingly Well

From single function to multi-device platform. The simplicity helped, not hindered.

3. Infrastructure as Code Enables Experimentation

Easy to spin up new functions, test ideas, tear down failures.

4. Event-Driven Architecture Emerges Naturally

When everything is a webhook or API call, event-driven patterns appear automatically.

The Future

Next integrations:

  • Home security system
  • Weather station data
  • Energy monitoring
  • Plant watering automation

The pattern remains the same:

  1. Find device with web interface
  2. Wrap in shell functions
  3. Deploy as Lambda
  4. Connect to event platform

The Meta-Lesson

I didn’t set out to build a platform. I solved one problem (router API), then another (Alexa integration), then another (LED notifications).

The platform emerged from solving real problems with simple tools.

This is how good architecture happens: not by grand design, but by consistent principles applied to real problems.


Sometimes the best platforms are the ones you don’t plan to build.