github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/pkg/hueemulator/upnp.go (about) 1 package hueemulator 2 3 import ( 4 "bytes" 5 "log" 6 "net" 7 "strings" 8 "text/template" 9 10 "github.com/gin-gonic/gin" 11 ) 12 13 const ( 14 upnp_multicast_address = "239.255.255.250:1900" 15 upnp_uri = "/upnp/setup.xml" 16 ) 17 18 //OPT: "http://schemas.upnp.org/upnp/1/0/"; ns=01 19 var responseTemplateText = `HTTP/1.1 200 OK 20 CACHE-CONTROL: max-age=86400 21 EXT: 22 LOCATION: http://{{.}} 23 SERVER: FreeRTOS/6.0.5, UPnP/1.0, IpBridge/0.1 24 hue-bridgeid: 001E06FFFE123456 25 ST: urn:schemas-upnp-org:device:basic:1 26 USN: uuid:Socket-1_0-221438K0100073::urn:schemas-upnp-org:device:basic:1 27 28 ` 29 30 //var setupTemplateText = `<?xml version="1.0"?> 31 //<root xmlns="urn:schemas-upnp-org:device-1-0"> 32 //<specVersion> 33 //<major>1</major> 34 //<minor>0</minor> 35 //</specVersion> 36 //<URLBase>http://{{.}}/</URLBase> 37 //<device> 38 //<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType> 39 //<friendlyName>huejack</friendlyName> 40 //<manufacturer>Royal Philips Electronics</manufacturer> 41 //<modelName>Philips hue bridge 2012</modelName> 42 //<modelNumber>929000226503</modelNumber> 43 //<UDN>uuid:f6543a06-800d-48ba-8d8f-bc2949eddc33</UDN> 44 //</device> 45 //</root>` 46 47 var setupTemplateText = ` 48 <?xml version="1.0"?> 49 <root xmlns="urn:schemas-upnp-org:device-1-0"> 50 <specVersion> 51 <major>1</major> 52 <minor>0</minor> 53 </specVersion> 54 <URLBase>http://{{.}}/</URLBase> 55 <device> 56 <deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType> 57 <friendlyName>Amazon-Echo-HA-Bridge (192.168.42.102)</friendlyName> 58 <manufacturer>Royal Philips Electronics</manufacturer> 59 <manufacturerURL>http://www.armzilla..com</manufacturerURL> 60 <modelDescription>Hue Emulator for Amazon Echo bridge</modelDescription> 61 <modelName>Philips hue bridge 2012</modelName> 62 <modelNumber>929000226503</modelNumber> 63 <modelURL>http://www.armzilla.com/amazon-echo-ha-bridge</modelURL> 64 <serialNumber>01189998819991197253</serialNumber> 65 <UDN>uuid:88f6698f-2c83-4393-bd03-cd54a9f8595</UDN> 66 <serviceList> 67 <service> 68 <serviceType>(null)</serviceType> 69 <serviceId>(null)</serviceId> 70 <controlURL>(null)</controlURL> 71 <eventSubURL>(null)</eventSubURL> 72 <SCPDURL>(null)</SCPDURL> 73 </service> 74 </serviceList> 75 <presentationURL>index.html</presentationURL> 76 <iconList> 77 <icon> 78 <mimetype>image/png</mimetype> 79 <height>48</height> 80 <width>48</width> 81 <depth>24</depth> 82 <url>hue_logo_0.png</url> 83 </icon> 84 <icon> 85 <mimetype>image/png</mimetype> 86 <height>120</height> 87 <width>120</width> 88 <depth>24</depth> 89 <url>hue_logo_3.png</url> 90 </icon> 91 </iconList> 92 </device> 93 </root>` 94 95 type upnpData struct { 96 Addr string 97 Uri string 98 } 99 100 var setupTemplate *template.Template 101 102 func upnpTemplateInit() { 103 var err error 104 setupTemplate, err = template.New("").Parse(setupTemplateText) 105 if err != nil { 106 log.Fatalln("upnpTemplateInit:", err) 107 } 108 } 109 110 func upnpSetup(addr string) gin.HandlerFunc { 111 return func(c *gin.Context) { 112 //w.Header().Set("Content-Type", "application/xml") 113 err := setupTemplate.Execute(c.Writer, addr) 114 if err != nil { 115 log.Fatalln("[WEB] upnpSetup:", err) 116 } 117 } 118 } 119 120 func upnpResponder(hostAddr string, endpoint string) { 121 responseTemplate, err := template.New("").Parse(responseTemplateText) 122 123 log.Println("[UPNP] listening...") 124 addr, err := net.ResolveUDPAddr("udp", upnp_multicast_address) 125 if err != nil { 126 log.Fatal(err) 127 } 128 l, err := net.ListenMulticastUDP("udp", nil, addr) 129 l.SetReadBuffer(1024) 130 131 for { 132 b := make([]byte, 1024) 133 n, src, err := l.ReadFromUDP(b) 134 if err != nil { 135 log.Fatal("[UPNP] ReadFromUDP failed:", err) 136 } 137 138 if strings.Contains(string(b[:n]), "MAN: \"ssdp:discover\"") { 139 c, err := net.DialUDP("udp", nil, src) 140 if err != nil { 141 log.Fatal("[UPNP] DialUDP failed:", err) 142 } 143 144 if debug { 145 log.Println("[UPNP] discovery request from", src) 146 } 147 148 // For whatever reason I can't execute the template using c as the reader, 149 // you HAVE to put it in a buffer first 150 // possible timing issue? 151 // don't believe me? try it 152 b := &bytes.Buffer{} 153 err = responseTemplate.Execute(b, hostAddr+endpoint) 154 if err != nil { 155 log.Fatal("[UPNP] execute template failed:", err) 156 } 157 c.Write(b.Bytes()) 158 } 159 } 160 }