├── LICENSE ├── cec-web.go └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Christian Brunner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /cec-web.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/jessevdk/go-flags" 6 | "github.com/chbmuc/cec" 7 | "os" 8 | ) 9 | 10 | type Options struct { 11 | Host string `short:"i" long:"ip" description:"ip to listen on" default:"127.0.0.1"` 12 | Port string `short:"p" long:"port" description:"tcp port to listen on" default:"8080"` 13 | Adapter string `short:"a" long:"adapter" description:"cec adapter to connect to [RPI, usb, ...]"` 14 | Name string `short:"n" long:"name" description:"OSD name to announce on the cec bus" default:"REST Gateway"` 15 | } 16 | 17 | var options Options 18 | var parser = flags.NewParser(&options, flags.Default) 19 | 20 | func main() { 21 | if _, err := parser.Parse(); err != nil { 22 | os.Exit(1) 23 | } 24 | 25 | cec.Open(options.Adapter, options.Name) 26 | 27 | r := gin.Default() 28 | r.GET("/info", info) 29 | r.GET("/power/:device", power_status) 30 | r.PUT("/power/:device", power_on) 31 | r.DELETE("/power/:device", power_off) 32 | r.PUT("/volume/up", vol_up) 33 | r.PUT("/volume/down", vol_down) 34 | r.PUT("/volume/mute", vol_mute) 35 | //r.POST("/key/:device", key_post) 36 | r.PUT("/key/:device/:key", key) 37 | r.POST("/transmit", transmit) 38 | 39 | r.Run(options.Host + ":" + options.Port) 40 | } 41 | 42 | func info(c *gin.Context) { 43 | c.JSON(200, cec.List()) 44 | } 45 | 46 | func power_on(c *gin.Context) { 47 | addr := cec.GetLogicalAddressByName(c.Params.ByName("device")) 48 | 49 | cec.PowerOn(addr) 50 | c.String(204, "") 51 | } 52 | 53 | func power_off(c *gin.Context) { 54 | addr := cec.GetLogicalAddressByName(c.Params.ByName("device")) 55 | 56 | cec.Standby(addr) 57 | c.String(204, "") 58 | } 59 | 60 | func power_status(c *gin.Context) { 61 | addr := cec.GetLogicalAddressByName(c.Params.ByName("device")) 62 | 63 | status := cec.GetDevicePowerStatus(addr) 64 | if status == "on" { 65 | c.String(204, "") 66 | } else if status == "standby" { 67 | c.String(404, "") 68 | } else { 69 | c.String(500, "invalid power state") 70 | } 71 | } 72 | 73 | func transmit(c *gin.Context) { 74 | var commands []string 75 | c.Bind(&commands) 76 | 77 | for _, val := range commands { 78 | cec.Transmit(val) 79 | } 80 | c.String(204, "") 81 | } 82 | 83 | func vol_up(c *gin.Context) { 84 | cec.VolumeUp() 85 | c.String(204, "") 86 | } 87 | 88 | func vol_down(c *gin.Context) { 89 | cec.VolumeDown() 90 | c.String(204, "") 91 | } 92 | 93 | func vol_mute(c *gin.Context) { 94 | cec.Mute() 95 | c.String(204, "") 96 | } 97 | 98 | func key(c *gin.Context) { 99 | addr := cec.GetLogicalAddressByName(c.Params.ByName("device")) 100 | key := c.Params.ByName("key") 101 | 102 | cec.Key(addr, key) 103 | c.String(204, "") 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cec-web 2 | ======= 3 | 4 | A REST micro webservice to control devices via the CEC bus in HDMI. 5 | 6 | Written in Go with some help from [Gin](http://gin-gonic.github.io/gin/), [Go-Flags](https://github.com/jessevdk/go-flags) and [cec.go](https://github.com/chbmuc/cec). 7 | 8 | Usage 9 | ===== 10 | 11 | Usage: 12 | cec-web [OPTIONS] 13 | 14 | Application Options: 15 | -i, --ip= ip to listen on (127.0.0.1) 16 | -p, --port= tcp port to listen on (8080) 17 | -a, --adapter= cec adapter to connect to [RPI, usb, ...] 18 | -n, --name= OSD name to announce on the cec bus (REST Gateway) 19 | 20 | 21 | JSON API 22 | ======== 23 | 24 | The app provides the following JSON based RESTful API: 25 | 26 | ## Scan CEC bus 27 | 28 | * ``GET /info`` - Information about all the connected devices on the CEC bus 29 | 30 | #### Resonse 31 | 32 | HTTP/1.1 200 OK 33 | 34 | ```json 35 | { 36 | "Playback":{ 37 | "OSDName":"REST Gateway", 38 | "Vendor":"Panasonic", 39 | "LogicalAddress":4, 40 | "ActiveSource":false, 41 | "PowerStatus":"on", 42 | "PhysicalAddress":"f.f.f.f" 43 | }, 44 | "TV":{ 45 | "OSDName":"TV", 46 | "Vendor":"Panasonic", 47 | "LogicalAddress":0, 48 | "ActiveSource":false, 49 | "PowerStatus":"standby", 50 | "PhysicalAddress":"0.0.0.0" 51 | } 52 | } 53 | ``` 54 | 55 | ## Power 56 | 57 | * ``GET /power/:device`` - Request device power status 58 | * ``PUT /power/:device`` - Power on device 59 | * ``DELETE /power/:device`` - Put device in standby 60 | 61 | ``:device`` is the name of the device on the CEC bus (see ``GET /info``) 62 | 63 | #### Responses 64 | 65 | success (PUT/DELETE); is powered on (GET) 66 | 67 | HTTP/1.1 204 No Content 68 | 69 | is in standy/no power (GET) 70 | 71 | HTTP/1.1 404 Not Found 72 | 73 | 74 | ## Volume (not supported by all devices) 75 | 76 | * ``PUT /volume/up`` - Increase volume 77 | * ``PUT /volume/down`` - Reduce volume 78 | * ``PUT /volume/mute`` - Mute/unmute audio 79 | 80 | #### Response 81 | 82 | HTTP/1.1 204 No Content 83 | 84 | ## Remote control 85 | 86 | * ``PUT /key/:device/:key`` - Send key press command followed by key release 87 | 88 | > ``:device`` is the name of the device on the CEC bus (see ``GET /info``) 89 | > ``:key`` is the name (e.g. ``down``) or the keycode in hex (e.g. ``0x00``) of a remote key 90 | 91 | #### Response 92 | 93 | HTTP/1.1 204 No Content 94 | 95 | ## Raw CEC commands 96 | 97 | * ``POST /transmit`` - Send a list of CEC commands over the bus 98 | 99 | data example: 100 | ```json 101 | [ 102 | "40:04", 103 | "40:64:00:48:65:6C:6C:6F:20:77:6F:72:6C:64" 104 | ] 105 | ``` 106 | 107 | Hint: Use [cec-o-matic](http://www.cec-o-matic.com/) to generate commands. 108 | --------------------------------------------------------------------------------