Add log consultation from GUI.

Add XMPP command support
This commit is contained in:
Chteufleur 2016-04-03 00:34:43 +02:00
parent 207971f2db
commit ea30512e65
18 changed files with 613 additions and 78 deletions

View File

@ -13,3 +13,7 @@ SessionGCMaxLifetime = 3600
SessionHashFunc = sha1
SessionHashKey = chucknorriswillkickyourassandeatyoursoul
SessionCookieLifeTime = 3600
JID = test@kingpenguin.tk
PWD = test
PORT = 5222

View File

@ -18,7 +18,7 @@ var (
)
func init() {
log.SetLogger("console", "")
log.SetLogger(variables.LogType, variables.LogParams)
}
type SensorPrint struct {

View File

@ -102,9 +102,7 @@ func (c *CommandRelayController) Prepare() {
func (c *CommandRelayController) Post() {
mac := c.Ctx.Input.Param(":sensor")
r := relay.GetRelayByMac(mac)
if r.Id != 0 {
httplib.Get("http://"+r.IpAddress+"/toggle").SetTimeout(3*time.Second, 3*time.Second).String()
}
r.Toggle()
c.Ctx.Output.Body([]byte(""))
}

View File

@ -5,6 +5,9 @@ import (
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
"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["dataCompteur"] = teleinfo.GetLastDataForCompteur(cpt.AdresseCompteur)
c.Data["compteurAdresse"] = cpt.AdresseCompteur
if cpt.Description != "" {
c.Data["compteurDescription"] = cpt.Description
} else {
c.Data["compteurDescription"] = cpt.AdresseCompteur
desc := cpt.Description
if desc == "" {
desc = cpt.AdresseCompteur
}
c.Data["compteurDescription"] = desc
dataPower := formatDataSensorTeleInfo(teleinfo.GetAllDataForCompteur(cpt.AdresseCompteur))
c.Data["dataPower"] = template.JS(dataPower)
}
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
}

64
controllers/viewLog.go Normal file
View File

@ -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(""))
}

View File

@ -5,6 +5,9 @@ import (
_ "git.kingpenguin.tk/chteufleur/datahouse.git/models/temperature"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/user"
_ "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/logs"
@ -18,7 +21,7 @@ var (
)
func init() {
log.SetLogger("console", "")
log.SetLogger(variables.LogType, variables.LogParams)
url := ""
db := ""
if database.DatabaseInstance == database.MySQL {
@ -51,6 +54,7 @@ func main() {
if !user.IsUserExist("admin") {
user.AddUser("admin", "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918")
}
go xmpp_manager.Run()
go watchlog.Run()
beego.Run()
}

View File

@ -2,9 +2,12 @@ package relay
import (
"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/utils"
"time"
)
type RelayTable struct {
@ -120,3 +123,11 @@ func DeleteSensor(id int64) {
o.Using(database.Alias)
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
}

View File

@ -6,6 +6,7 @@ import (
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
"time"
)
@ -26,7 +27,7 @@ var (
)
func init() {
log.SetLogger("console", "")
log.SetLogger(variables.LogType, variables.LogParams)
orm.RegisterModel(new(TeleinfoTable), new(CompteurTeleinfoTable))
orm.DefaultRowsLimit = 4500
@ -114,6 +115,11 @@ func GetLastDataForCompteur(adresseCompteur string) *TeleinfoTable {
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.Using(database.Alias)
o.Delete(&CompteurTeleinfoTable{AdresseCompteur: adresse})
DeleteDataCompteur(adresse)
}
func DeleteCompteur(compteurId int64) {
compteur := GetSensor(compteurId)
o := orm.NewOrm()
o.Using(database.Alias)
o.Delete(&CompteurTeleinfoTable{Id: compteurId})
DeleteDataCompteur(compteur.AdresseCompteur)
}

View File

@ -6,6 +6,7 @@ import (
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
"time"
)
@ -25,7 +26,7 @@ var (
)
func init() {
log.SetLogger("console", "")
log.SetLogger(variables.LogType, variables.LogParams)
orm.RegisterModel(new(TempTableTmp))
}

View File

@ -6,6 +6,7 @@ import (
"git.kingpenguin.tk/chteufleur/datahouse.git/models/database"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/utils"
"git.kingpenguin.tk/chteufleur/datahouse.git/models/variables"
"time"
)
@ -23,7 +24,7 @@ var (
)
func init() {
log.SetLogger("console", "")
log.SetLogger(variables.LogType, variables.LogParams)
orm.RegisterModel(new(TempTable))
orm.DefaultRowsLimit = 4500
}

View File

@ -1,14 +1,24 @@
package variables
const (
Version = "0.0.5.0"
Version = "0.1.2"
SessionName = "Session_Data_House"
sensorMacRegex = ":sensor([0-9A-Fa-f:]+)"
logFile = "file"
LogFileName = "filename"
LogFilePath = "datahouse.log"
logConsole = "console"
)
var (
/*
Routes
*/
RootRoute = "/"
AddTempRoute = "/add/temp/" + sensorMacRegex + "/:val([0-9]+)"
@ -20,6 +30,8 @@ var (
ViewRelayRoute = "/view/relay/" + sensorMacRegex
ViewTeleinfosRoute = "/view/teleinfo"
ViewTeleinfoRoute = "/view/teleinfo/:compteur([0-9A-Fa-f:]+)"
ViewLogRoute = "/view/log"
WebSocketLogRoute = "/view/log/join"
CommandRelayRoute = "/command/relay/" + sensorMacRegex
@ -28,4 +40,12 @@ var (
LoginRouteNoRegex = "/login"
UserRoute = "/user"
/*
Logs
*/
LogType = logFile
LogParams = "{\""+LogFileName+"\":\""+LogFilePath+"\"}"
)

View File

@ -16,6 +16,8 @@ func init() {
beego.Router(variables.ViewTempRoute, &controllers.ViewTempController{})
beego.Router(variables.ViewRelaysRoute, &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{})
@ -25,4 +27,5 @@ func init() {
beego.Router(variables.SensorsRoute, &controllers.SensorsController{})
beego.Router(variables.LoginRoute, &controllers.LoginController{})
beego.Router(variables.UserRoute, &controllers.UserController{})
}

View File

@ -4,20 +4,25 @@
* Version 1.0
*/
/*
* TODO : Gestion du temps pour n'envoyer que toute les minutes (ou un truc du genre)
*/
#include <ESP8266WiFi.h>
#define startFrame 0x02
#define endFrame 0x03
#define startLine 0x0A
#define endLine 0x0D
#define space 0x20
//----------------------------------------------------
/*
const char* ssid = "TNCAP3F2E03";
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 int httpPort = 8080;
const char* host = "datahouse.kingpenguin.tk";
const int httpPort = 80;
const int DEFAULT_INTERVAL = 60000; // 60 sec
//----------------------------------------------------
@ -37,7 +42,7 @@ void sleepSec(int sec) {
long nextInterval;
long nextInterval = millis() + DEFAULT_INTERVAL;
void sendDataToServer() {
// Use WiFiClient class to create TCP connections
@ -46,18 +51,12 @@ void sendDataToServer() {
Serial.print("connection failed on host ");
Serial.print(host);
Serial.print(":");
Serial.println(host);
Serial.println(httpPort);
return;
}
// 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;
ADCO = "";
OPTARIF = "";
BASE = "";
HCHC = "";
HCHP = "";
Serial.print("Requesting URL: ");
Serial.println(url);
@ -85,6 +84,19 @@ void sendDataToServer() {
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() {
Serial.begin(1200);
@ -110,51 +122,82 @@ void setup() {
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;
void loop() {
if (Serial.available() > 0) {
String str = Serial.readStringUntil('\n');
if (millis() >= nextInterval) {
bool sendable = false;
int i = str.indexOf("ADCO");
if (i != -1) {
i = i + 4 +1;
ADCO = str.substring(i, i+12);
while (charIn != startLine) {
charIn = Serial.read() & 0x7F;
}
i = str.indexOf("OPTARIF");
if (i != -1) {
i = i + 7 +1;
OPTARIF = str.substring(i, i+4);
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++;
}
i = str.indexOf("BASE");
if (i != -1) {
i = i + 4 +1;
BASE = str.substring(i, i+9);
} else {
index++;
}
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();
}
}
}
}
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() {
GetTeleInfo();
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) {
sendDataToServer();
}
}
}

View File

@ -16,7 +16,7 @@
{{if .IsViewTemp}}
class="active"
{{end}}
><a href="/view/temp">Temperatures</a></li>
><a href="/view/temp">Températures</a></li>
<li
{{if .IsViewRelay}}
@ -33,6 +33,11 @@
</ul>
<ul class="nav navbar-nav navbar-right">
{{if .IsAuthentificated}}
<li
{{if .IsLog}}
class="active"
{{end}}
><a href="/view/log">Logs</a></li>
<li
{{if .IsUser}}
class="active"

View File

@ -1,5 +1,94 @@
{{template "base/base.html" .}}
{{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}}
{{define "extrajs"}}
{{end}}
@ -54,6 +143,8 @@
<h4>Option base: <small>{{.dataCompteur.OptionBase}}</small></h4>
<h4>Heure pleine: <small>{{.dataCompteur.HeurePleinne}} Wh</small></h4>
<h4>Heure creuse: <small>{{.dataCompteur.HeureCreuse}} Wh</small></h4>
<div style="margin-top: 30px;" id="graphe"></div>
</div>
{{end}}
{{end}}

21
views/watchlog.tpl Normal file
View File

@ -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}}

37
watchlog/watchlog.go Normal file
View File

@ -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
}
}
}

182
xmpp/xmpp.go Normal file
View File

@ -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
}
}