parent
207971f2db
commit
ea30512e65
|
|
@ -13,3 +13,7 @@ SessionGCMaxLifetime = 3600
|
||||||
SessionHashFunc = sha1
|
SessionHashFunc = sha1
|
||||||
SessionHashKey = chucknorriswillkickyourassandeatyoursoul
|
SessionHashKey = chucknorriswillkickyourassandeatyoursoul
|
||||||
SessionCookieLifeTime = 3600
|
SessionCookieLifeTime = 3600
|
||||||
|
|
||||||
|
JID = test@kingpenguin.tk
|
||||||
|
PWD = test
|
||||||
|
PORT = 5222
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLogger("console", "")
|
log.SetLogger(variables.LogType, variables.LogParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SensorPrint struct {
|
type SensorPrint struct {
|
||||||
|
|
|
||||||
|
|
@ -102,9 +102,7 @@ func (c *CommandRelayController) Prepare() {
|
||||||
func (c *CommandRelayController) Post() {
|
func (c *CommandRelayController) Post() {
|
||||||
mac := c.Ctx.Input.Param(":sensor")
|
mac := c.Ctx.Input.Param(":sensor")
|
||||||
r := relay.GetRelayByMac(mac)
|
r := relay.GetRelayByMac(mac)
|
||||||
if r.Id != 0 {
|
r.Toggle()
|
||||||
httplib.Get("http://"+r.IpAddress+"/toggle").SetTimeout(3*time.Second, 3*time.Second).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Ctx.Output.Body([]byte(""))
|
c.Ctx.Output.Body([]byte(""))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ import (
|
||||||
|
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/teleinfo"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/teleinfo"
|
||||||
|
|
||||||
|
"html/template"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
//——————————————————————————————————————————————————————————————————————————————
|
//——————————————————————————————————————————————————————————————————————————————
|
||||||
|
|
@ -57,12 +60,48 @@ func (c *ViewTeleinfoController) Get() {
|
||||||
c.Data["isCompteurSelected"] = true
|
c.Data["isCompteurSelected"] = true
|
||||||
c.Data["dataCompteur"] = teleinfo.GetLastDataForCompteur(cpt.AdresseCompteur)
|
c.Data["dataCompteur"] = teleinfo.GetLastDataForCompteur(cpt.AdresseCompteur)
|
||||||
c.Data["compteurAdresse"] = cpt.AdresseCompteur
|
c.Data["compteurAdresse"] = cpt.AdresseCompteur
|
||||||
if cpt.Description != "" {
|
desc := cpt.Description
|
||||||
c.Data["compteurDescription"] = cpt.Description
|
if desc == "" {
|
||||||
} else {
|
desc = cpt.AdresseCompteur
|
||||||
c.Data["compteurDescription"] = cpt.AdresseCompteur
|
|
||||||
}
|
}
|
||||||
|
c.Data["compteurDescription"] = desc
|
||||||
|
dataPower := formatDataSensorTeleInfo(teleinfo.GetAllDataForCompteur(cpt.AdresseCompteur))
|
||||||
|
c.Data["dataPower"] = template.JS(dataPower)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.TplNames = "teleinfo.tpl"
|
c.TplNames = "teleinfo.tpl"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func formatDataSensorTeleInfo(values []teleinfo.TeleinfoTable) string {
|
||||||
|
ret := ""
|
||||||
|
for a := 0; a < 2; a++ {
|
||||||
|
ret += "{name : \""
|
||||||
|
if a == 0 {
|
||||||
|
ret += "Heure Pleines"
|
||||||
|
} else {
|
||||||
|
ret += "Heure Creuses"
|
||||||
|
}
|
||||||
|
ret += "\",marker : {enabled : true, radius : 3}, data : ["
|
||||||
|
for i := 0; i < len(values); i++ {
|
||||||
|
if i > 0 {
|
||||||
|
ret += ","
|
||||||
|
}
|
||||||
|
// TODO faire la dérivé de la puissance pour avoir les variations plutot que l'évolution de la puissance
|
||||||
|
horodate := strconv.FormatInt((values[i].HorodateGMT.Unix()+int64(timezoneOffset))*1000, 10)
|
||||||
|
value := ""
|
||||||
|
if a == 0 {
|
||||||
|
value = strconv.FormatInt(values[i].HeurePleinne, 10)
|
||||||
|
} else {
|
||||||
|
value = strconv.FormatInt(values[i].HeureCreuse, 10)
|
||||||
|
}
|
||||||
|
ret += "[" + horodate + "," + value + "]"
|
||||||
|
}
|
||||||
|
ret += "]}"
|
||||||
|
|
||||||
|
if a == 0 {
|
||||||
|
ret += ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/watchlog"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type WebSocketController struct {
|
||||||
|
beego.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *WebSocketController) Prepare() {
|
||||||
|
sess := c.GetSession(variables.SessionName)
|
||||||
|
if sess == nil {
|
||||||
|
c.Redirect(variables.LoginRouteNoRegex+variables.UserRoute, 302)
|
||||||
|
} else {
|
||||||
|
c.Data["IsAuthentificated"] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["IsLog"] = true
|
||||||
|
c.Data["version"] = variables.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get method handles GET requests for WebSocketController.
|
||||||
|
func (c *WebSocketController) Get() {
|
||||||
|
c.Data["hostWS"] = "ws://"+c.Ctx.Request.Host+variables.WebSocketLogRoute
|
||||||
|
c.TplNames = "watchlog.tpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Join method handles WebSocket requests for WebSocketController.
|
||||||
|
func (this *WebSocketController) Join() {
|
||||||
|
// Upgrade from http request to WebSocket.
|
||||||
|
ws, err := websocket.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request, nil, 1024, 1024)
|
||||||
|
if _, ok := err.(websocket.HandshakeError); ok {
|
||||||
|
http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400)
|
||||||
|
return
|
||||||
|
} else if err != nil {
|
||||||
|
beego.Error("Cannot setup WebSocket connection:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
watchlog.ListWebSocket.PushFront(ws)
|
||||||
|
|
||||||
|
|
||||||
|
// Message receive loop.
|
||||||
|
for {
|
||||||
|
_, _, err := ws.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.Ctx.Output.Body([]byte(""))
|
||||||
|
}
|
||||||
8
main.go
8
main.go
|
|
@ -5,6 +5,9 @@ import (
|
||||||
_ "git.kingpenguin.tk/chteufleur/datahouse.git/models/temperature"
|
_ "git.kingpenguin.tk/chteufleur/datahouse.git/models/temperature"
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/user"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/user"
|
||||||
_ "git.kingpenguin.tk/chteufleur/datahouse.git/routers"
|
_ "git.kingpenguin.tk/chteufleur/datahouse.git/routers"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/xmpp"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/watchlog"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/astaxie/beego/logs"
|
"github.com/astaxie/beego/logs"
|
||||||
|
|
@ -18,7 +21,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLogger("console", "")
|
log.SetLogger(variables.LogType, variables.LogParams)
|
||||||
url := ""
|
url := ""
|
||||||
db := ""
|
db := ""
|
||||||
if database.DatabaseInstance == database.MySQL {
|
if database.DatabaseInstance == database.MySQL {
|
||||||
|
|
@ -51,6 +54,7 @@ func main() {
|
||||||
if !user.IsUserExist("admin") {
|
if !user.IsUserExist("admin") {
|
||||||
user.AddUser("admin", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918")
|
user.AddUser("admin", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918")
|
||||||
}
|
}
|
||||||
|
go xmpp_manager.Run()
|
||||||
|
go watchlog.Run()
|
||||||
beego.Run()
|
beego.Run()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,12 @@ package relay
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
|
"github.com/astaxie/beego/httplib"
|
||||||
|
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||||
|
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RelayTable struct {
|
type RelayTable struct {
|
||||||
|
|
@ -120,3 +123,11 @@ func DeleteSensor(id int64) {
|
||||||
o.Using(database.Alias)
|
o.Using(database.Alias)
|
||||||
o.Delete(&RelayTable{Id: id})
|
o.Delete(&RelayTable{Id: id})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (relay *RelayTable) Toggle() (error) {
|
||||||
|
var err error
|
||||||
|
if relay.Id != 0 {
|
||||||
|
_, err = httplib.Get("http://"+relay.IpAddress+"/toggle").SetTimeout(3*time.Second, 3*time.Second).String()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -26,7 +27,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLogger("console", "")
|
log.SetLogger(variables.LogType, variables.LogParams)
|
||||||
orm.RegisterModel(new(TeleinfoTable), new(CompteurTeleinfoTable))
|
orm.RegisterModel(new(TeleinfoTable), new(CompteurTeleinfoTable))
|
||||||
orm.DefaultRowsLimit = 4500
|
orm.DefaultRowsLimit = 4500
|
||||||
|
|
||||||
|
|
@ -114,6 +115,11 @@ func GetLastDataForCompteur(adresseCompteur string) *TeleinfoTable {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeleteDataCompteur(adresseCompteur string) {
|
||||||
|
o := orm.NewOrm()
|
||||||
|
o.Using(database.Alias)
|
||||||
|
o.Delete(&TeleinfoTable{AdresseCompteur: adresseCompteur})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -220,10 +226,15 @@ func DeleteCompteurByAdresse(adresse string) {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
o.Using(database.Alias)
|
o.Using(database.Alias)
|
||||||
o.Delete(&CompteurTeleinfoTable{AdresseCompteur: adresse})
|
o.Delete(&CompteurTeleinfoTable{AdresseCompteur: adresse})
|
||||||
|
|
||||||
|
DeleteDataCompteur(adresse)
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteCompteur(compteurId int64) {
|
func DeleteCompteur(compteurId int64) {
|
||||||
|
compteur := GetSensor(compteurId)
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
o.Using(database.Alias)
|
o.Using(database.Alias)
|
||||||
o.Delete(&CompteurTeleinfoTable{Id: compteurId})
|
o.Delete(&CompteurTeleinfoTable{Id: compteurId})
|
||||||
|
|
||||||
|
DeleteDataCompteur(compteur.AdresseCompteur)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -25,7 +26,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLogger("console", "")
|
log.SetLogger(variables.LogType, variables.LogParams)
|
||||||
orm.RegisterModel(new(TempTableTmp))
|
orm.RegisterModel(new(TempTableTmp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
|
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
|
||||||
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -23,7 +24,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLogger("console", "")
|
log.SetLogger(variables.LogType, variables.LogParams)
|
||||||
orm.RegisterModel(new(TempTable))
|
orm.RegisterModel(new(TempTable))
|
||||||
orm.DefaultRowsLimit = 4500
|
orm.DefaultRowsLimit = 4500
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,51 @@
|
||||||
package variables
|
package variables
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.0.5.0"
|
Version = "0.1.2"
|
||||||
|
|
||||||
SessionName = "Session_Data_House"
|
SessionName = "Session_Data_House"
|
||||||
|
|
||||||
sensorMacRegex = ":sensor([0-9A-Fa-f:]+)"
|
sensorMacRegex = ":sensor([0-9A-Fa-f:]+)"
|
||||||
|
|
||||||
|
logFile = "file"
|
||||||
|
LogFileName = "filename"
|
||||||
|
LogFilePath = "datahouse.log"
|
||||||
|
logConsole = "console"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
RootRoute = "/"
|
/*
|
||||||
|
————————————————————————————————————————————————————————————————————————————————
|
||||||
|
Routes
|
||||||
|
————————————————————————————————————————————————————————————————————————————————
|
||||||
|
*/
|
||||||
|
RootRoute = "/"
|
||||||
|
|
||||||
AddTempRoute = "/add/temp/" + sensorMacRegex + "/:val([0-9]+)"
|
AddTempRoute = "/add/temp/" + sensorMacRegex + "/:val([0-9]+)"
|
||||||
AddRelayRoute = "/add/relay/" + sensorMacRegex
|
AddRelayRoute = "/add/relay/" + sensorMacRegex
|
||||||
TeleinfoAddRoute = "/teleinfo/add"
|
TeleinfoAddRoute = "/teleinfo/add"
|
||||||
|
|
||||||
ViewTempRoute = "/view/temp"
|
ViewTempRoute = "/view/temp"
|
||||||
ViewRelaysRoute = "/view/relay"
|
ViewRelaysRoute = "/view/relay"
|
||||||
ViewRelayRoute = "/view/relay/" + sensorMacRegex
|
ViewRelayRoute = "/view/relay/" + sensorMacRegex
|
||||||
ViewTeleinfosRoute = "/view/teleinfo"
|
ViewTeleinfosRoute = "/view/teleinfo"
|
||||||
ViewTeleinfoRoute = "/view/teleinfo/:compteur([0-9A-Fa-f:]+)"
|
ViewTeleinfoRoute = "/view/teleinfo/:compteur([0-9A-Fa-f:]+)"
|
||||||
|
ViewLogRoute = "/view/log"
|
||||||
|
WebSocketLogRoute = "/view/log/join"
|
||||||
|
|
||||||
CommandRelayRoute = "/command/relay/" + sensorMacRegex
|
CommandRelayRoute = "/command/relay/" + sensorMacRegex
|
||||||
|
|
||||||
SensorsRoute = "/sensors"
|
SensorsRoute = "/sensors"
|
||||||
LoginRoute = "/login/:route(.*)"
|
LoginRoute = "/login/:route(.*)"
|
||||||
LoginRouteNoRegex = "/login"
|
LoginRouteNoRegex = "/login"
|
||||||
UserRoute = "/user"
|
UserRoute = "/user"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
————————————————————————————————————————————————————————————————————————————————
|
||||||
|
Logs
|
||||||
|
————————————————————————————————————————————————————————————————————————————————
|
||||||
|
*/
|
||||||
|
LogType = logFile
|
||||||
|
LogParams = "{\""+LogFileName+"\":\""+LogFilePath+"\"}"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ func init() {
|
||||||
beego.Router(variables.ViewTempRoute, &controllers.ViewTempController{})
|
beego.Router(variables.ViewTempRoute, &controllers.ViewTempController{})
|
||||||
beego.Router(variables.ViewRelaysRoute, &controllers.ViewRelayController{})
|
beego.Router(variables.ViewRelaysRoute, &controllers.ViewRelayController{})
|
||||||
beego.Router(variables.ViewRelayRoute, &controllers.ViewRelayController{})
|
beego.Router(variables.ViewRelayRoute, &controllers.ViewRelayController{})
|
||||||
|
beego.Router(variables.ViewLogRoute, &controllers.WebSocketController{})
|
||||||
|
beego.Router(variables.WebSocketLogRoute, &controllers.WebSocketController{}, "get:Join")
|
||||||
|
|
||||||
beego.Router(variables.CommandRelayRoute, &controllers.CommandRelayController{})
|
beego.Router(variables.CommandRelayRoute, &controllers.CommandRelayController{})
|
||||||
|
|
||||||
|
|
@ -25,4 +27,5 @@ func init() {
|
||||||
beego.Router(variables.SensorsRoute, &controllers.SensorsController{})
|
beego.Router(variables.SensorsRoute, &controllers.SensorsController{})
|
||||||
beego.Router(variables.LoginRoute, &controllers.LoginController{})
|
beego.Router(variables.LoginRoute, &controllers.LoginController{})
|
||||||
beego.Router(variables.UserRoute, &controllers.UserController{})
|
beego.Router(variables.UserRoute, &controllers.UserController{})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,25 @@
|
||||||
* Version 1.0
|
* Version 1.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO : Gestion du temps pour n'envoyer que toute les minutes (ou un truc du genre)
|
|
||||||
*/
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
#define startFrame 0x02
|
||||||
|
#define endFrame 0x03
|
||||||
|
#define startLine 0x0A
|
||||||
|
#define endLine 0x0D
|
||||||
|
#define space 0x20
|
||||||
|
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
|
|
||||||
|
/*
|
||||||
const char* ssid = "TNCAP3F2E03";
|
const char* ssid = "TNCAP3F2E03";
|
||||||
const char* password = "73ABCCAA87";
|
const char* password = "73ABCCAA87";
|
||||||
|
*/
|
||||||
|
const char* ssid = "L0AD";
|
||||||
|
const char* password = "";
|
||||||
|
|
||||||
//const char* host = "datahouse.kingpenguin.tk";
|
|
||||||
const char* host = "192.168.1.143";
|
const char* host = "datahouse.kingpenguin.tk";
|
||||||
const int httpPort = 8080;
|
const int httpPort = 80;
|
||||||
const int DEFAULT_INTERVAL = 60000; // 60 sec
|
const int DEFAULT_INTERVAL = 60000; // 60 sec
|
||||||
|
|
||||||
//----------------------------------------------------
|
//----------------------------------------------------
|
||||||
|
|
@ -37,7 +42,7 @@ void sleepSec(int sec) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
long nextInterval;
|
long nextInterval = millis() + DEFAULT_INTERVAL;
|
||||||
|
|
||||||
void sendDataToServer() {
|
void sendDataToServer() {
|
||||||
// Use WiFiClient class to create TCP connections
|
// Use WiFiClient class to create TCP connections
|
||||||
|
|
@ -46,18 +51,12 @@ void sendDataToServer() {
|
||||||
Serial.print("connection failed on host ");
|
Serial.print("connection failed on host ");
|
||||||
Serial.print(host);
|
Serial.print(host);
|
||||||
Serial.print(":");
|
Serial.print(":");
|
||||||
Serial.println(host);
|
Serial.println(httpPort);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We now create a URI for the request
|
// We now create a URI for the request
|
||||||
// TODO a finir
|
|
||||||
String url = "/teleinfo/add?ADCO="+ADCO+"&OPTARIF="+OPTARIF+"&BASE="+BASE+"&HCHC="+HCHC+"&HCHP="+HCHP;
|
String url = "/teleinfo/add?ADCO="+ADCO+"&OPTARIF="+OPTARIF+"&BASE="+BASE+"&HCHC="+HCHC+"&HCHP="+HCHP;
|
||||||
ADCO = "";
|
|
||||||
OPTARIF = "";
|
|
||||||
BASE = "";
|
|
||||||
HCHC = "";
|
|
||||||
HCHP = "";
|
|
||||||
|
|
||||||
Serial.print("Requesting URL: ");
|
Serial.print("Requesting URL: ");
|
||||||
Serial.println(url);
|
Serial.println(url);
|
||||||
|
|
@ -85,6 +84,19 @@ void sendDataToServer() {
|
||||||
nextInterval = millis() + nextInterval;
|
nextInterval = millis() + nextInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isDigitSelf(char c) {
|
||||||
|
return c >= 48 && c <= 57;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isNumberSelf(String s) {
|
||||||
|
for (int i=0; i<(s.length()); i++){
|
||||||
|
if (!isDigitSelf(s[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(1200);
|
Serial.begin(1200);
|
||||||
|
|
@ -110,48 +122,79 @@ void setup() {
|
||||||
Serial.println(WiFi.localIP());
|
Serial.println(WiFi.localIP());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String label = "";
|
||||||
|
String value = "";
|
||||||
|
char checksum = 0;
|
||||||
|
|
||||||
|
void GetTeleInfo() {
|
||||||
|
String TeleInfo = "";
|
||||||
|
char charIn = 0;
|
||||||
|
|
||||||
|
int index = 0; // 0 - label ; 1 - value ; 2 - checksum
|
||||||
|
label = "";
|
||||||
|
value = "";
|
||||||
|
checksum = 0;
|
||||||
|
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
while (charIn != startLine) {
|
||||||
|
charIn = Serial.read() & 0x7F;
|
||||||
|
}
|
||||||
|
while (charIn != endLine) {
|
||||||
|
// label
|
||||||
|
if (Serial.available() > 0) {
|
||||||
|
charIn = Serial.read() & 0x7F;
|
||||||
|
if (charIn != space) {
|
||||||
|
if (index == 0) {
|
||||||
|
label += charIn;
|
||||||
|
} else if (index == 1) {
|
||||||
|
value += charIn;
|
||||||
|
} else if (index == 2) {
|
||||||
|
checksum = charIn;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool checkSumVerif() {
|
||||||
|
char sum=0;
|
||||||
|
String trame = label + " " + value;
|
||||||
|
for (int i=0; i<(trame.length()); i++){
|
||||||
|
sum += trame[i];
|
||||||
|
}
|
||||||
|
sum = (sum & 0x3F) + 0x20;
|
||||||
|
return sum == checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
if (Serial.available() > 0) {
|
GetTeleInfo();
|
||||||
String str = Serial.readStringUntil('\n');
|
if (checkSumVerif()) {
|
||||||
|
Serial.println(label+" "+value+" "+checksum);
|
||||||
|
|
||||||
|
if (label == "ADCO" && isNumberSelf(value)) {
|
||||||
|
ADCO = value;
|
||||||
|
}
|
||||||
|
if (label == "OPTARIF") {
|
||||||
|
OPTARIF = value;
|
||||||
|
}
|
||||||
|
if (label == "BASE") {
|
||||||
|
BASE = value;
|
||||||
|
}
|
||||||
|
if (label == "HCHC" && isNumberSelf(value)) {
|
||||||
|
HCHC = value;
|
||||||
|
}
|
||||||
|
if (label == "HCHP" && isNumberSelf(value)) {
|
||||||
|
HCHP = value;
|
||||||
|
}
|
||||||
|
|
||||||
if (millis() >= nextInterval) {
|
if (millis() >= nextInterval) {
|
||||||
bool sendable = false;
|
sendDataToServer();
|
||||||
|
|
||||||
int i = str.indexOf("ADCO");
|
|
||||||
if (i != -1) {
|
|
||||||
i = i + 4 +1;
|
|
||||||
ADCO = str.substring(i, i+12);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = str.indexOf("OPTARIF");
|
|
||||||
if (i != -1) {
|
|
||||||
i = i + 7 +1;
|
|
||||||
OPTARIF = str.substring(i, i+4);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = str.indexOf("BASE");
|
|
||||||
if (i != -1) {
|
|
||||||
i = i + 4 +1;
|
|
||||||
BASE = str.substring(i, i+9);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = str.indexOf("HCHC");
|
|
||||||
if (i != -1) {
|
|
||||||
i = i + 4 +1;
|
|
||||||
HCHC = str.substring(i, i+9);
|
|
||||||
}
|
|
||||||
|
|
||||||
i = str.indexOf("HCHP");
|
|
||||||
if (i != -1) {
|
|
||||||
i = i + 4 +1;
|
|
||||||
HCHP = str.substring(i, i+9);
|
|
||||||
sendable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (sendable && ADCO != "") {
|
|
||||||
sendDataToServer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
{{if .IsViewTemp}}
|
{{if .IsViewTemp}}
|
||||||
class="active"
|
class="active"
|
||||||
{{end}}
|
{{end}}
|
||||||
><a href="/view/temp">Temperatures</a></li>
|
><a href="/view/temp">Températures</a></li>
|
||||||
|
|
||||||
<li
|
<li
|
||||||
{{if .IsViewRelay}}
|
{{if .IsViewRelay}}
|
||||||
|
|
@ -33,6 +33,11 @@
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
{{if .IsAuthentificated}}
|
{{if .IsAuthentificated}}
|
||||||
|
<li
|
||||||
|
{{if .IsLog}}
|
||||||
|
class="active"
|
||||||
|
{{end}}
|
||||||
|
><a href="/view/log">Logs</a></li>
|
||||||
<li
|
<li
|
||||||
{{if .IsUser}}
|
{{if .IsUser}}
|
||||||
class="active"
|
class="active"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,94 @@
|
||||||
{{template "base/base.html" .}}
|
{{template "base/base.html" .}}
|
||||||
{{define "meta"}}
|
{{define "meta"}}
|
||||||
|
<script type="text/javascript" src="/static/js/jquery-1.10.2.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/highstock/js/highstock.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/highstock/js/themes/grid.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/highstock/js/modules/exporting.js"></script>
|
||||||
|
<script src="http://code.highcharts.com/highcharts.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () {
|
||||||
|
chart1 = new Highcharts.StockChart({
|
||||||
|
chart: {
|
||||||
|
renderTo : 'graphe',
|
||||||
|
load : function () {
|
||||||
|
// set up the updating of the chart each second
|
||||||
|
var series = this.series[0];
|
||||||
|
setInterval(function () {
|
||||||
|
var x = (new Date()).getTime(), // current time
|
||||||
|
y = Math.round(Math.random() * 100);
|
||||||
|
series.addPoint([x, y], true, true);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
buttons: [{
|
||||||
|
count: 3,
|
||||||
|
type: 'hour',
|
||||||
|
text: '3h'
|
||||||
|
},{
|
||||||
|
count: 6,
|
||||||
|
type: 'hour',
|
||||||
|
text: '6h'
|
||||||
|
},{
|
||||||
|
count: 12,
|
||||||
|
type: 'hour',
|
||||||
|
text: '12h'
|
||||||
|
}, {
|
||||||
|
count: 1,
|
||||||
|
type: 'day',
|
||||||
|
text: '1j'
|
||||||
|
}, {
|
||||||
|
count: 2,
|
||||||
|
type: 'day',
|
||||||
|
text: '2j'
|
||||||
|
}, {
|
||||||
|
count: 3,
|
||||||
|
type: 'day',
|
||||||
|
text: '3j',
|
||||||
|
}, {
|
||||||
|
count: 5,
|
||||||
|
type: 'day',
|
||||||
|
text: '5j'
|
||||||
|
}, {
|
||||||
|
count: 7,
|
||||||
|
type: 'day',
|
||||||
|
text: '7j'
|
||||||
|
}, {
|
||||||
|
count: 1,
|
||||||
|
type: 'month',
|
||||||
|
text: '1m'
|
||||||
|
}, {
|
||||||
|
type: 'all',
|
||||||
|
text: 'All'
|
||||||
|
}],
|
||||||
|
selected: 5
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
title: {
|
||||||
|
text: 'Puissance (W)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'datetime'
|
||||||
|
},
|
||||||
|
scrollbar : {
|
||||||
|
enabled : false
|
||||||
|
},
|
||||||
|
legend : {
|
||||||
|
enabled : true,
|
||||||
|
layout: 'vertical',
|
||||||
|
verticalAlign : 'middle',
|
||||||
|
align : 'right'
|
||||||
|
},
|
||||||
|
series : [ {{.dataPower}} ]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Highcharts.setOptions({
|
||||||
|
global: {
|
||||||
|
useUTC: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{define "extrajs"}}
|
{{define "extrajs"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
@ -54,6 +143,8 @@
|
||||||
<h4>Option base: <small>{{.dataCompteur.OptionBase}}</small></h4>
|
<h4>Option base: <small>{{.dataCompteur.OptionBase}}</small></h4>
|
||||||
<h4>Heure pleine: <small>{{.dataCompteur.HeurePleinne}} Wh</small></h4>
|
<h4>Heure pleine: <small>{{.dataCompteur.HeurePleinne}} Wh</small></h4>
|
||||||
<h4>Heure creuse: <small>{{.dataCompteur.HeureCreuse}} Wh</small></h4>
|
<h4>Heure creuse: <small>{{.dataCompteur.HeureCreuse}} Wh</small></h4>
|
||||||
|
|
||||||
|
<div style="margin-top: 30px;" id="graphe"></div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
{{template "base/base.html" .}}
|
||||||
|
{{define "meta"}}
|
||||||
|
{{end}}
|
||||||
|
{{define "extrajs"}}
|
||||||
|
<script>
|
||||||
|
var logs = document.getElementById("log")
|
||||||
|
var ws = new WebSocket("{{.hostWS}}");
|
||||||
|
ws.onopen = function(evt) {
|
||||||
|
}
|
||||||
|
ws.onclose = function(evt) {
|
||||||
|
ws = null;
|
||||||
|
}
|
||||||
|
ws.onmessage = function(evt) {
|
||||||
|
log.innerHTML = evt.data + "\n" + logs.innerHTML;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
|
{{define "body"}}
|
||||||
|
<textarea id="log" readonly="readonly" rows="20" style="width: 100%;">
|
||||||
|
</textarea>
|
||||||
|
{{end}}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package watchlog
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/hpcloud/tail"
|
||||||
|
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
|
||||||
|
"container/list"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ListWebSocket = list.New()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func Run() {
|
||||||
|
t, _ := tail.TailFile(variables.LogFilePath, tail.Config{Follow: true})
|
||||||
|
for line := range t.Lines {
|
||||||
|
broadcastWebSocket(line.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func broadcastWebSocket(message string) {
|
||||||
|
for sub := ListWebSocket.Front(); sub != nil; sub = sub.Next() {
|
||||||
|
// Immediately send event to WebSocket users.
|
||||||
|
ws := sub.Value.(*websocket.Conn)
|
||||||
|
err := ws.WriteMessage(websocket.TextMessage, []byte(message))
|
||||||
|
if err != nil {
|
||||||
|
toRemove := sub
|
||||||
|
sub = sub.Prev()
|
||||||
|
ListWebSocket.Remove(toRemove)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
package xmpp_manager
|
||||||
|
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/astaxie/beego/logs"
|
||||||
|
|
||||||
|
"git.kingpenguin.tk/chteufleur/go-xmpp.git"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/relay"
|
||||||
|
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
|
||||||
|
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const (
|
||||||
|
Status_online = ""
|
||||||
|
Status_offline = ""
|
||||||
|
Status_away = "away"
|
||||||
|
Status_chat = "chat"
|
||||||
|
Status_do_not_disturb = "dnd"
|
||||||
|
Status_extended_away = "xa"
|
||||||
|
|
||||||
|
Type_available = ""
|
||||||
|
Type_unavailable = "unavailable"
|
||||||
|
Type_subscribe = "subscribe"
|
||||||
|
Type_subscribed = "subscribed"
|
||||||
|
Type_unsubscribe = "unsubscribe"
|
||||||
|
Type_unsubscribed = "unsubscribed"
|
||||||
|
Type_probe = "probe"
|
||||||
|
Type_error = "error"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
log = logs.NewLogger(10000)
|
||||||
|
|
||||||
|
JidStr = beego.AppConfig.String("JID")
|
||||||
|
passwdStr = beego.AppConfig.String("PWD")
|
||||||
|
serverPort = beego.AppConfig.String("PORT")
|
||||||
|
|
||||||
|
jid xmpp.JID
|
||||||
|
stream = new(xmpp.Stream)
|
||||||
|
client = new(xmpp.XMPP)
|
||||||
|
|
||||||
|
Debug = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
log.SetLogger(variables.LogType, variables.LogParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func must(v interface{}, err error) interface{} {
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Must error : ", err)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run() {
|
||||||
|
// Create stream and configure it as a component connection.
|
||||||
|
jid = must(xmpp.ParseJID(JidStr)).(xmpp.JID)
|
||||||
|
stream = must(xmpp.NewStream(jid.Domain+":"+serverPort, &xmpp.StreamConfig{LogStanzas: Debug})).(*xmpp.Stream)
|
||||||
|
client = must(xmpp.NewClientXMPP(stream, jid, passwdStr, &xmpp.ClientConfig{InsecureSkipVerify: true})).(*xmpp.XMPP)
|
||||||
|
|
||||||
|
mainXMPP()
|
||||||
|
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func mainXMPP() {
|
||||||
|
SendPresence(Status_online, Type_available, "")
|
||||||
|
|
||||||
|
for x := range client.In {
|
||||||
|
switch v := x.(type) {
|
||||||
|
case *xmpp.Presence:
|
||||||
|
|
||||||
|
case *xmpp.Message:
|
||||||
|
log.Info("Message received : %s", v.Body)
|
||||||
|
|
||||||
|
case *xmpp.Iq:
|
||||||
|
// TODO check if the caller has privilege to ask
|
||||||
|
switch v.PayloadName().Space {
|
||||||
|
case xmpp.NsDiscoItems:
|
||||||
|
execDiscoCommand(v)
|
||||||
|
|
||||||
|
case xmpp.NodeAdHocCommand:
|
||||||
|
execCommandAdHoc(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Info("recv: %v", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func SendPresence(status, tpye, message string) {
|
||||||
|
client.Out <- xmpp.Presence{From: jid.Domain, Show: status, Type: tpye, Status: message}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func execDiscoCommand(iq *xmpp.Iq) {
|
||||||
|
log.Info("Discovery item iq received")
|
||||||
|
reply := iq.Response(xmpp.IqTypeResult)
|
||||||
|
discoItem := &xmpp.DiscoItems{Node: xmpp.NodeAdHocCommand}
|
||||||
|
|
||||||
|
relays := relay.GetAllRelay()
|
||||||
|
for _, r := range relays {
|
||||||
|
discoI := &xmpp.DiscoItem{JID: client.JID.Full(), Node: r.Mac, Name: "Relay : "}
|
||||||
|
if (r.Description == "") {
|
||||||
|
discoI.Name += r.Mac
|
||||||
|
} else {
|
||||||
|
discoI.Name += r.Description
|
||||||
|
}
|
||||||
|
discoItem.Item = append(discoItem.Item, *discoI)
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.PayloadEncode(discoItem)
|
||||||
|
client.Out <- reply
|
||||||
|
}
|
||||||
|
|
||||||
|
func execCommandAdHoc(iq *xmpp.Iq) {
|
||||||
|
adHoc := &xmpp.AdHocCommand{}
|
||||||
|
iq.PayloadDecode(adHoc)
|
||||||
|
log.Info("Commande Ad-Hoc reçut. Node : %s", adHoc.Node)
|
||||||
|
|
||||||
|
// For now, we know that the node is the Mac address for a relay
|
||||||
|
relais := relay.GetRelayByMac(adHoc.Node)
|
||||||
|
descriptionRelais := relais.Description
|
||||||
|
if descriptionRelais == "" {
|
||||||
|
descriptionRelais = relais.Mac
|
||||||
|
}
|
||||||
|
if adHoc.SessionId == "" && adHoc.Action == xmpp.ActionAdHocExecute {
|
||||||
|
// First step in the command
|
||||||
|
if relais.Id != 0 {
|
||||||
|
reply := iq.Response(xmpp.IqTypeResult)
|
||||||
|
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocExecute, SessionId: xmpp.SessionId()/*+";"+relais.Mac*/}
|
||||||
|
|
||||||
|
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocForm, Title: "Commande relais "+descriptionRelais}
|
||||||
|
field := &xmpp.AdHocField{Var: "command", Label: "Commande a executer", Type: "list-single"}
|
||||||
|
fieldOption := &xmpp.AdHocFieldOption{Value: "toggle"}
|
||||||
|
field.Options = append(field.Options, *fieldOption)
|
||||||
|
cmdXForm.Fields = append(cmdXForm.Fields, *field)
|
||||||
|
// TODO, ajouter des commandes pour allumer X seconde (par exemple)
|
||||||
|
|
||||||
|
cmd.XForm = *cmdXForm
|
||||||
|
|
||||||
|
reply.PayloadEncode(cmd)
|
||||||
|
client.Out <- reply
|
||||||
|
}
|
||||||
|
} else if adHoc.Action == xmpp.ActionAdHocExecute {
|
||||||
|
// Last step in the command
|
||||||
|
|
||||||
|
err := relais.Toggle()
|
||||||
|
|
||||||
|
reply := iq.Response(xmpp.IqTypeResult)
|
||||||
|
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCompleted, SessionId: adHoc.SessionId}
|
||||||
|
|
||||||
|
cmdXForm := &xmpp.AdHocXForm{Type: xmpp.TypeAdHocResult, Title: "Commande relais "+descriptionRelais}
|
||||||
|
cmd.XForm = *cmdXForm
|
||||||
|
|
||||||
|
note := &xmpp.AdHocNote{Type: xmpp.TypeAdHocNoteInfo}
|
||||||
|
if err == nil {
|
||||||
|
note.Value = "Commande effectuée avec succes !"
|
||||||
|
} else {
|
||||||
|
note.Value = "Une erreur c'est produite à l'exécution de la commande…"
|
||||||
|
}
|
||||||
|
cmd.Note = *note
|
||||||
|
|
||||||
|
reply.PayloadEncode(cmd)
|
||||||
|
client.Out <- reply
|
||||||
|
} else if adHoc.Action == xmpp.ActionAdHocCancel {
|
||||||
|
// command canceled
|
||||||
|
reply := iq.Response(xmpp.IqTypeResult)
|
||||||
|
cmd := &xmpp.AdHocCommand{Node: adHoc.Node, Status: xmpp.StatusAdHocCanceled, SessionId: adHoc.SessionId}
|
||||||
|
reply.PayloadEncode(cmd)
|
||||||
|
client.Out <- reply
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue