Skip to content

endreszabo/relayctl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

relayctl

An intelligent relay control system for managing power states of hardware devices with optimized boot/shutdown sequences.

Features

  • Dependency Management: Devices can depend on other devices (e.g., computer needs network switch)
  • Optimized Boot Timing: Calculates optimal start times for dependent devices to minimize total boot time
  • Lock-based Control: Multiple users/processes can request device power with lock IDs
  • Graceful Shutdown: Devices shut down after a delay when all locks are released
  • Cooldown Protection: Prevents rapid on/off cycling to protect hardware
  • Event Hooks: Observe and react to relay state changes
  • Flexible Logging: Integrate with your favorite logging library

Installation

go get github.com/endreszabo/relayctl

Quick Start

package main

import (
    "context"
    "fmt"
    "time"
    "github.com/endreszabo/relayctl/relay"
)

func main() {
    // Create a network switch that takes 30 seconds to boot
    network := relay.NewRelay("network", nil,
        relay.WithBootDelay(30*time.Second),
        relay.WithCooldownPeriod(2*time.Second),
        relay.WithHardwareControl(
            func() error { fmt.Println("Turning on network"); return nil },
            func() error { fmt.Println("Turning off network"); return nil },
        ),
    )

    // Create a computer that depends on the network
    // Will start at T=5s (30s - 25s) so both are ready at T=30s
    computer := relay.NewRelay("computer", nil,
        relay.WithBootDelay(25*time.Second),
        relay.WithDependencies(network),
        relay.WithHardwareControl(
            func() error { fmt.Println("Turning on computer"); return nil },
            func() error { fmt.Println("Turning off computer"); return nil },
        ),
    )

    ctx := context.Background()

    // Turn on the computer (network starts automatically)
    if err := computer.TurnOn(ctx, "user1"); err != nil {
        fmt.Printf("Error: %v\n", err)
    }

    // ... use the devices ...

    // Turn off when done
    computer.TurnOff("user1")
}

Concepts

State Machine

Each relay goes through these states:

StateOff → StateBooting → StateOn → [locks empty, wait powerOffDelay] → StateCoolingDown → StateOff

Dependencies

When a relay has dependencies, they are started automatically with optimized timing:

// Computer needs network to be ready
computer := relay.NewRelay("computer", nil,
    relay.WithBootDelay(25*time.Second),
    relay.WithDependencies(network),
)

The system calculates the optimal start time so the computer finishes booting exactly when the network is ready, minimizing total startup time.

Locks

Multiple users can hold locks on a relay simultaneously. The relay only turns off after all locks are released:

computer.TurnOn(ctx, "user1")
computer.TurnOn(ctx, "user2")  // Second lock

computer.TurnOff("user1")      // Still stays on (user2 still has lock)
computer.TurnOff("user2")      // Now it turns off after powerOffDelay

Configuration Options

Use functional options to configure relays:

Option Description Default
WithBootDelay(d) Time required for the relay to boot 0
WithCooldownPeriod(d) Minimum time between off and on 0
WithPowerOffDelay(d) Delay before actual shutdown after last lock released 0
WithHardwareControl(on, off) Hardware control functions No-op
WithDependencies(...) Dependency relays none
WithLogger(logger) Logger for operations NoOpLogger
WithEventHandler(handler) Event handler for state changes NoOpEventHandler
WithController(ctrl) Central controller (optional) nil

Advanced Usage

Custom Logging

type MyLogger struct{}

func (l *MyLogger) Debug(msg string, args ...interface{}) {
    // Your logging implementation
}

func (l *MyLogger) Info(msg string, args ...interface{}) {
    // Your logging implementation
}

func (l *MyLogger) Error(msg string, args ...interface{}) {
    // Your logging implementation
}

relay := relay.NewRelay("id", nil,
    relay.WithLogger(&MyLogger{}),
)

Event Handlers

type MyEventHandler struct{}

func (h *MyEventHandler) OnBootComplete(relayID string, duration time.Duration) {
    fmt.Printf("🎉 %s booted in %v\n", relayID, duration)
}

func (h *MyEventHandler) OnStateChange(relayID string, oldState, newState relay.RelayState) {
    fmt.Printf("%s: %s → %s\n", relayID, oldState, newState)
}

// Implement other EventHandler methods...

relay := relay.NewRelay("id", nil,
    relay.WithEventHandler(&MyEventHandler{}),
)

Demo

Build and run the demo application:

go run cmd/demo/main.go

API Documentation

Full API documentation is available at godoc.org.

License

[Your License Here]

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages