initial import

This commit is contained in:
2020-12-23 10:11:11 +01:00
commit be83b43a59
5600 changed files with 577973 additions and 0 deletions

20
src/config.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import (
"log"
"github.com/spf13/viper"
)
func readConfig() {
viper.SetConfigName("openpdu.yaml") // name of config file (without extension)
viper.SetConfigType("yaml")
viper.AddConfigPath("/etc/openpdu/") // path to look for the config file in
viper.AddConfigPath(".") // optionally look for config in the working directory
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
log.Printf("Fatal error config file: %s \n", err)
}
viper.SetDefault("hostname", "openpdu")
}

91
src/display.go Normal file
View File

@@ -0,0 +1,91 @@
package main
import (
"image"
"image/color"
"log"
"net"
"golang.org/x/image/font"
"golang.org/x/image/font/basicfont"
"golang.org/x/image/math/fixed"
// "periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/devices/ssd1306"
)
func addLabel(img *image.RGBA, x, y int, label string) {
col := color.RGBA{200, 100, 0, 255}
point := fixed.Point26_6{fixed.Int26_6(x * 64), fixed.Int26_6(y * 64)}
d := &font.Drawer{
Dst: img,
Src: image.NewUniform(col),
Face: basicfont.Face7x13,
Dot: point,
}
d.DrawString(label)
}
func getIPs() map[string]string {
out := map[string]string{}
ifaces, _ := net.Interfaces()
// handle err
for _, i := range ifaces {
if i.Name == "lo" {
continue
}
addrs, _ := i.Addrs()
// handle err
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
// process IP address
if ip.To4() == nil {
continue
}
if len(out) < 1 {
out[i.Name] = ip.String()
}
}
}
return out
}
func disp() {
opts := ssd1306.Opts{
W: 128,
H: 32,
Rotated: false,
Sequential: true,
SwapTopBottom: false,
}
// Open a handle to a ssd1306 connected on the I²C bus:
dev, err := ssd1306.NewI2C(i2cbus, &opts)
if err != nil {
log.Fatal(err)
}
img := image.NewRGBA(image.Rect(0, 0, 128, 32))
ips := getIPs()
lineHeight := 12
// posX := 10
posX := 12
posY := lineHeight
// for name, ip := range ips {
for _, ip := range ips {
// addLabel(img, posX, posY, name)
// posY += lineHeight
addLabel(img, posX, posY, ip)
posY += lineHeight
}
dev.Draw(img.Bounds(), img, image.Point{})
}

118
src/i2c.go Normal file
View File

@@ -0,0 +1,118 @@
package main
import (
"errors"
"log"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/host"
)
// I2CBoard bla
type I2CBoard struct {
i2cdev i2c.Dev
channels uint
data []byte
inverted bool
}
// MyBoard bla
var MyBoard = I2CBoard{
channels: 8,
inverted: true,
}
var i2cbus i2c.Bus
func (b I2CBoard) channelStatus(ch uint) (bool, error) {
if b.channels <= 0 {
return false, errors.New("Board without channels")
}
if ch >= b.channels {
return false, errors.New("Invalid channel")
}
write := []byte{0x0A}
err := b.i2cdev.Tx(write, b.data)
if err != nil {
return false, err
}
byteToConsider := ch / b.channels
value := (b.data[byteToConsider] >> (ch % 8) & 1) == 1
if b.inverted {
value = !value
}
return value, nil
}
func (b I2CBoard) channelToggle(ch uint) error {
var mask byte
if b.channels <= 0 {
return errors.New("Board without channels")
}
if ch >= b.channels {
return errors.New("Invalid channel")
}
// if b.data == nil {
_, _ = b.channelStatus(ch)
// }
byteToConsider := ch / b.channels
mask = 1 << (ch % 8)
v := b.data[byteToConsider]
v ^= mask
b.data[byteToConsider] = v
write := append([]byte{0x09}, b.data...)
_, err := b.i2cdev.Write(write)
if err != nil {
return err
}
return nil
}
func initI2C() {
var err error
// Make sure periph is initialized.
if _, err = host.Init(); err != nil {
log.Fatal(err)
}
// Use i2creg I²C bus registry to find the first available I²C bus.
// i2cbus, err = i2creg.Open("/dev/i2c-1")
i2cbus, err = i2creg.Open("")
if err != nil {
log.Fatal(err)
}
// defer i2cbus.Close()
// bus 0
// Dev is a valid conn.Conn.
mydevice := &i2c.Dev{Addr: 0x27, Bus: i2cbus}
// Send a command 0x10 and expect a 5 bytes reply.
// write := []byte{0x10}
write := []byte{0x0, 0x0}
// read := make([]byte, 5)
// if err := d.Tx(write, read); err != nil {
if _, err := mydevice.Write(write); err != nil {
log.Fatal(err)
}
MyBoard.i2cdev = *mydevice
MyBoard.data = make([]byte, (MyBoard.channels-1)/8+1)
go func() {
var i uint
for i = 0; i < 8; i++ {
v, err := MyBoard.channelStatus(i)
if err != nil {
log.Fatal(err)
}
log.Printf("Channel %d status: %v", i, v)
}
}()
}

42
src/main.go Normal file
View File

@@ -0,0 +1,42 @@
package main
import (
// "encoding/json"
"log"
// "periph.io/x/periph"
"github.com/spf13/viper"
)
// Dictionary aaa
type Dictionary map[string]interface{}
func main() {
readConfig()
nam := viper.Get("hostname")
log.Printf("hostname: %v\n", nam)
initI2C()
go disp()
startServer()
}
// https://github.com/ColorlibHQ/AdminLTE/archive/v2.4.17.tar.gz
/* TODO
- config reset gpio
- classi per board
- classi per outlet
- fai funzionare toggle
- scan i2c
- impostazioni log
- impostazioni mqtt
*/

33
src/mqtt.go Normal file
View File

@@ -0,0 +1,33 @@
package main
import (
"fmt"
"os"
MQTT "github.com/eclipse/paho.mqtt.golang"
)
func init() {
// set the protocol, ip and port of the broker.
opts := MQTT.NewClientOptions().AddBroker("tcp://localhost:1883")
// set the id to the client.
opts.SetClientID("Device-pub")
// create a new client.
c := MQTT.NewClient(opts)
token := c.Connect()
token.Wait()
if token.Error() != nil {
fmt.Println(token.Error())
os.Exit(1)
}
message := "hello this is the trial message"
c.Publish("some_topic", 0, false, message)
//c.Subscribe("some_topic", 0, nil);
c.Disconnect(250)
}
// https://girishjoshi.io/post/golang-paho-mqtt/

24
src/syslog.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"log"
syslog "github.com/RackSec/srslog"
)
func init() {
w, err := syslog.Dial("", "", syslog.LOG_ERR, "testtag")
if err != nil {
log.Fatal("failed to connect to syslog:", err)
}
defer w.Close()
w.Alert("this is an alert")
w.Crit("this is critical")
w.Err("this is an error")
w.Warning("this is a warning")
w.Notice("this is a notice")
w.Info("this is info")
w.Debug("this is debug")
w.Write([]byte("these are some bytes"))
}

113
src/webui.go Normal file
View File

@@ -0,0 +1,113 @@
package main
import (
"fmt"
"log"
"net/http"
"strconv"
"github.com/go-macaron/pongo2"
"gopkg.in/macaron.v1"
)
func statusPage(ctx *macaron.Context) {
ctx.Data["pluglist"] = []Dictionary{
{"id": 1, "description": "p1"},
{"id": 2, "description": "p2"},
{"id": 3, "description": "p3"},
{"id": 4, "description": "p4"},
{"id": 5, "description": "p5"},
{"id": 6, "description": "p6"},
{"id": 7, "description": "p7"},
{"id": 8, "description": "p8"},
}
ctx.HTML(200, "status") // 200 is the response code.
}
func jsonStatus(ctx *macaron.Context) {
p0, err := MyBoard.channelStatus(0)
if err != nil {
log.Fatal(err)
}
p1, err := MyBoard.channelStatus(1)
if err != nil {
log.Fatal(err)
}
p2, err := MyBoard.channelStatus(2)
if err != nil {
log.Fatal(err)
}
p3, err := MyBoard.channelStatus(3)
if err != nil {
log.Fatal(err)
}
p4, err := MyBoard.channelStatus(4)
if err != nil {
log.Fatal(err)
}
p5, err := MyBoard.channelStatus(5)
if err != nil {
log.Fatal(err)
}
p6, err := MyBoard.channelStatus(6)
if err != nil {
log.Fatal(err)
}
p7, err := MyBoard.channelStatus(7)
if err != nil {
log.Fatal(err)
}
ctx.JSON(http.StatusOK, Dictionary{
"data": [][]string{
{"0", "p0", fmt.Sprint(p0)},
{"1", "p1", fmt.Sprint(p1)},
{"2", "p2", fmt.Sprint(p2)},
{"3", "p3", fmt.Sprint(p3)},
{"4", "p4", fmt.Sprint(p4)},
{"5", "p5", fmt.Sprint(p5)},
{"6", "p6", fmt.Sprint(p6)},
{"7", "p7", fmt.Sprint(p7)},
},
})
}
func jsonOutletToggle(ctx *macaron.Context) {
id, err := strconv.ParseUint(ctx.Params(":id"), 10, 64)
if err != nil {
log.Fatal(err)
}
err = MyBoard.channelToggle(uint(id))
if err != nil {
log.Fatal(err)
}
ctx.JSON(http.StatusOK, Dictionary{
"data": "ok",
})
}
func startServer() {
m := macaron.Classic()
m.Use(pongo2.Pongoer())
m.Use(macaron.Static("static"))
// m.Get("/", myHandler)
m.Get("/", statusPage)
m.Get("/json/status", jsonStatus)
m.Post("/json/outlet/:id/toggle", jsonOutletToggle)
m.Get("/boards", func(ctx *macaron.Context) {
ctx.HTML(200, "boards") // 200 is the response code.
})
log.Println("Server is running...")
log.Println(http.ListenAndServe("0.0.0.0:4000", m))
}