// Process PollNotification task
func (service *Service) processPollNotification(task Task) (notifications []core.Notification, err error) {
	// check task error first
	if task.err != nil {
		err = task.err
		return
	}

	// check status code
	if task.response.StatusCode != http.StatusOK {
		log.Warnf("REST: unexpected /notification/poll status %s",
			task.response.Status)
		err = fmt.Errorf("unexpected status: %s",
			task.response.Status)
		return
	}

	// unmarshal
	err = json.Unmarshal(task.body, &notifications)
	if err != nil {
		log.Warnf("REST: failed to parse /notification/poll body (error: %s)", err)
		return
	}

	return
}
// CommandUpdate() function updates the command.
func (service *Service) UpdateCommand(device *core.Device, command *core.Command, timeout time.Duration) (err error) {
	task, err := service.prepareUpdateCommand(device, command)
	if err != nil {
		log.Warnf("WS: failed to prepare /command/update task (error: %s)", err)
		return
	}

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /command/update task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		err = service.processUpdateCommand(task)
		if err != nil {
			log.Warnf("WS: failed to process /command/update task (error: %s)", err)
			return
		}
	}

	return
}
// InsertNotification() function inserts the notification.
func (service *Service) InsertNotification(device *core.Device, notification *core.Notification, timeout time.Duration) (err error) {
	task, err := service.prepareInsertNotification(device, notification)
	if err != nil {
		log.Warnf("WS: failed to prepare /notification/insert task (error: %s)", err)
		return
	}

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /notification/insert task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		err = service.processInsertNotification(task, notification)
		if err != nil {
			log.Warnf("WS: failed to process /notification/insert task (error: %s)", err)
			return
		}
	}

	return
}
// Prepare InsertNotification task
func (service *Service) prepareInsertNotification(device *core.Device, notification *core.Notification) (task Task, err error) {
	// create request
	url := fmt.Sprintf("%s/device/%s/notification", service.baseUrl, device.Id)

	// do not put some fields to the request body
	notification = &core.Notification{Name: notification.Name,
		Parameters: notification.Parameters}

	body, err := json.Marshal(notification)
	if err != nil {
		log.Warnf("REST: failed to format /notification/insert request (error: %s)", err)
		return
	}

	task.request, err = http.NewRequest("POST", url, bytes.NewBuffer(body))
	if err != nil {
		log.Warnf("REST: failed to create /notification/insert request (error: %s)", err)
		return
	}
	task.request.Header.Add("Content-Type", "application/json")

	// authorization
	service.prepareAuthorization(task.request, device)

	return
}
Example #5
0
// GetNetwork() function get the network data.
func (service *Service) GetNetwork(networkId uint64, timeout time.Duration) (network *core.Network, err error) {
	log.Tracef("REST: getting network %d...", networkId)

	task, err := service.prepareGetNetwork(networkId)
	if err != nil {
		log.Warnf("REST: failed to prepare /network/get task (error: %s)", err)
		return
	}

	select {
	case <-time.After(timeout):
		log.Warnf("REST: failed to wait %s for /network/get task", timeout)
		err = fmt.Errorf("timed out")

	case task = <-service.doAsync(task):
		network = &core.Network{Id: networkId}
		err = service.processGetNetwork(task, network)
		if err != nil {
			log.Warnf("REST: failed to process /network/get task (error: %s)", err)
			return
		}
	}

	return
}
// GetNotification() function get the notification data.
func (service *Service) GetNotification(device *core.Device, notificationId uint64, timeout time.Duration) (notification *core.Notification, err error) {
	log.Tracef("REST: getting notification %q/%d...", device.Id, notificationId)

	task, err := service.prepareGetNotification(device, notificationId)
	if err != nil {
		log.Warnf("REST: failed to prepare /notification/get task (error: %s)", err)
		return
	}

	select {
	case <-time.After(timeout):
		log.Warnf("REST: failed to wait %s for /notification/get task", timeout)
		err = fmt.Errorf("timed out")

	case task = <-service.doAsync(task):
		notification = &core.Notification{Id: notificationId}
		err = service.processGetNotification(task, notification)
		if err != nil {
			log.Warnf("REST: failed to process /notification/get task (error: %s)", err)
			return
		}
	}

	return
}
Example #7
0
// GetServerInfo() function gets the main server's information.
func (service *Service) GetServerInfo(timeout time.Duration) (info *core.ServerInfo, err error) {
	task, err := service.prepareGetServerInfo()
	if err != nil {
		log.Warnf("WS: failed to prepare /info task (error: %s)", err)
		return
	}

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /info task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		info = &core.ServerInfo{}
		err = service.processGetServerInfo(task, info)
		if err != nil {
			log.Warnf("WS: failed to process /info task (error: %s)", err)
			return
		}
	}

	return
}
// UnsubscribeCommand() function updates the command.
func (service *Service) UnsubscribeCommands(device *core.Device, timeout time.Duration) (err error) {
	task, err := service.prepareUnsubscribeCommand(device)
	if err != nil {
		log.Warnf("WS: failed to prepare /command/unsubscribe task (error: %s)", err)
		return
	}

	service.removeCommandListener(device.Id)

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /command/unsubscribe task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		err = service.processUnsubscribeCommand(task)
		if err != nil {
			log.Warnf("WS: failed to process /command/unsubscribe task (error: %s)", err)
			return
		}
	}

	return
}
// Process InsertNetwork task
func (service *Service) processInsertNetwork(task Task, network *core.Network) (err error) {
	// check task error first
	if task.err != nil {
		err = task.err
		return
	}

	// check status code
	if task.response.StatusCode < http.StatusOK ||
		task.response.StatusCode > http.StatusPartialContent {
		log.Warnf("REST: unexpected /network/insert status %s",
			task.response.Status)
		err = fmt.Errorf("unexpected status: %s",
			task.response.Status)
		return
	}

	// unmarshal
	err = json.Unmarshal(task.body, network)
	if err != nil {
		log.Warnf("REST: failed to parse /network/insert body (error: %s)", err)
		return
	}

	return
}
Example #10
0
// GetDevice() function get the device data.
func (service *Service) GetDevice(deviceId, deviceKey string, timeout time.Duration) (device *core.Device, err error) {
	log.Tracef("REST: getting device %q...", deviceId)

	task, err := service.prepareGetDevice(deviceId, deviceKey)
	if err != nil {
		log.Warnf("REST: failed to prepare /device/get task (error: %s)", err)
		return
	}

	select {
	case <-time.After(timeout):
		log.Warnf("REST: failed to wait %s for /device/get task", timeout)
		err = fmt.Errorf("timed out")

	case task = <-service.doAsync(task):
		device = &core.Device{Id: deviceId, Key: deviceKey}
		err = service.processGetDevice(task, device)
		if err != nil {
			log.Warnf("REST: failed to process /device/get task (error: %s)", err)
			return
		}
	}

	return
}
// RegisterDevice() function registers the device.
func (service *Service) RegisterDevice(device *core.Device, timeout time.Duration) (err error) {
	task, err := service.prepareRegisterDevice(device)
	if err != nil {
		log.Warnf("WS: failed to prepare /device/register task (error: %s)", err)
		return
	}

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /device/register task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		err = service.processRegisterDevice(task)
		if err != nil {
			log.Warnf("WS: failed to process /device/register task (error: %s)", err)
			return
		}
	}

	return
}
Example #12
0
// Process GetCommand task
func (service *Service) processGetCommand(task Task, command *core.Command) (err error) {
	// check task error first
	if task.err != nil {
		err = task.err
		return
	}

	// check status code
	if task.response.StatusCode != http.StatusOK {
		log.Warnf("REST: unexpected /command/get status %s",
			task.response.Status)
		err = fmt.Errorf("unexpected status: %s",
			task.response.Status)
		return
	}

	// unmarshal
	err = json.Unmarshal(task.body, command)
	if err != nil {
		log.Warnf("REST: failed to parse /command/get body (error: %s)", err)
		return
	}

	return
}
Example #13
0
// Process GetDeviceList task
func (service *Service) processGetDeviceList(task Task) (devices []core.Device, err error) {
	// check task error first
	if task.err != nil {
		err = task.err
		return
	}

	// check status code
	if task.response.StatusCode != http.StatusOK {
		log.Warnf("REST: unexpected /device/list status %s",
			task.response.Status)
		err = fmt.Errorf("unexpected status: %s",
			task.response.Status)
		return
	}

	// unmarshal
	err = json.Unmarshal(task.body, &devices)
	if err != nil {
		log.Warnf("REST: failed to parse /device/list body (error: %s)", err)
		return
	}

	return
}
// Prepare InsertCommand task
func (service *Service) prepareInsertCommand(device *core.Device, command *core.Command) (task Task, err error) {
	// create request
	url := fmt.Sprintf("%s/device/%s/command", service.baseUrl, device.Id)

	// do not put some fields to the request body
	command = &core.Command{Name: command.Name,
		Parameters: command.Parameters,
		Lifetime:   command.Lifetime}

	body, err := json.Marshal(command)
	if err != nil {
		log.Warnf("REST: failed to format /command/insert request (error: %s)", err)
		return
	}

	task.request, err = http.NewRequest("POST", url, bytes.NewBuffer(body))
	if err != nil {
		log.Warnf("REST: failed to create /command/insert request (error: %s)", err)
		return
	}
	task.request.Header.Add("Content-Type", "application/json")

	// authorization
	service.prepareAuthorization(task.request, device)

	return
}
Example #15
0
// GetCommand() function get the command data.
func (service *Service) GetCommand(device *core.Device, commandId uint64, timeout time.Duration) (command *core.Command, err error) {
	log.Debugf("REST: getting command %q/%d...", device.Id, commandId)

	task, err := service.prepareGetCommand(device, commandId)
	if err != nil {
		log.Warnf("REST: failed to prepare /command/get task (error: %s)", err)
		return
	}

	select {
	case <-time.After(timeout):
		log.Warnf("REST: failed to wait %s for /command/get task", timeout)
		err = fmt.Errorf("timed out")

	case task = <-service.doAsync(task):
		command = &core.Command{Id: commandId}
		err = service.processGetCommand(task, command)
		if err != nil {
			log.Warnf("REST: failed to process /command/get task (error: %s)", err)
			return
		}
	}

	return
}
Example #16
0
// Do a request/task asynchronously
func (service *Service) doAsync(task Task) <-chan Task {
	ch := make(chan Task, 1)

	go func() {
		defer func() { ch <- task }()

		log.Tracef("REST: sending: %+v", task.request)
		task.response, task.err = service.client.Do(task.request)
		if task.err != nil {
			log.Warnf("REST: failed to do %s %s request (error: %s)",
				task.request.Method, task.request.URL, task.err)
			return
		}
		log.Tracef("REST: got %s %s response: %+v",
			task.request.Method, task.request.URL, task.response)

		// read body
		defer task.response.Body.Close()
		task.body, task.err = ioutil.ReadAll(task.response.Body)
		if task.err != nil {
			log.Warnf("REST: failed to read %s %s response body (error: %s)",
				task.request.Method, task.request.URL, task.err)
			return
		}

		log.Debugf("REST: got %s %s body: %s",
			task.request.Method, task.request.URL, string(task.body))
	}()

	return ch
}
Example #17
0
// TX thread
func (service *Service) doTX() {
	for {
		select {
		case task, ok := <-service.tx:
			if !ok || task == nil {
				log.Infof("WS: TX thread stopped")
				service.conn.Close() // TODO: send Close frame?
				return
			}

			body, err := task.Format()
			if err != nil {
				log.Warnf("WS: failed to format message (error: %s)", err)
				continue // TODO: return?
			}

			log.Tracef("WS: sending message: %s", string(body))
			err = service.conn.WriteMessage(websocket.TextMessage, body)
			if err != nil {
				log.Warnf("WS: failed to send message (error: %s)", err)
				continue // TODO: return?
			}

			//			case <-service.pingTimer.C:
			//			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
			//				log.Warnf("WS: could not write ping message (error: %s)", err)
			//				return
			//			}
		}
	}
}
Example #18
0
// GetDevice() function gets the device information.
func (service *Service) GetDevice(deviceId, deviceKey string, timeout time.Duration) (device *core.Device, err error) {
	device = &core.Device{Id: deviceId, Key: deviceKey}
	task, err := service.prepareGetDevice(device)
	if err != nil {
		log.Warnf("WS: failed to prepare /device/get task (error: %s)", err)
		return
	}

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /device/get task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		err = service.processGetDevice(task, device)
		if err != nil {
			log.Warnf("WS: failed to process /device/get task (error: %s)", err)
			return
		}
	}

	return
}
Example #19
0
// GetServerInfo() function gets the main server's information.
func (service *Service) GetServerInfo(timeout time.Duration) (info *core.ServerInfo, err error) {
	log.Tracef("REST: getting server info...")

	task, err := service.prepareGetServerInfo()
	if err != nil {
		log.Warnf("REST: failed to prepare /info task (error: %s)", err)
		return
	}

	select {
	case <-time.After(timeout):
		log.Warnf("REST: failed to wait %s for /info task", timeout)
		err = fmt.Errorf("timed out")

	case task = <-service.doAsync(task):
		info = &core.ServerInfo{}
		err = service.processGetServerInfo(task, info)
		if err != nil {
			log.Warnf("REST: failed to process /info task (error: %s)", err)
			return
		}
	}

	return
}
// SubscribeCommand() function updates the command.
func (service *Service) SubscribeCommands(device *core.Device, timestamp string, timeout time.Duration) (listener *core.CommandListener, err error) {
	task, err := service.prepareSubscribeCommand(device, timestamp)
	if err != nil {
		log.Warnf("WS: failed to prepare /command/subscribe task (error: %s)", err)
		return
	}

	// add to the TX pipeline
	service.tx <- task

	select {
	case <-time.After(timeout):
		log.Warnf("WS: failed to wait %s for /command/subscribe task", timeout)
		err = fmt.Errorf("timed out")

	case <-task.done:
		err = service.processSubscribeCommand(task)
		if err != nil {
			log.Warnf("WS: failed to process /command/subscribe task (error: %s)", err)
			return
		}

		// done, create listener
		listener = core.NewCommandListener()
		service.insertCommandListener(device.Id, listener)
	}

	return
}
Example #21
0
// main loop
func mainLoop(bus *dbus.Conn, service devicehive.Service, config conf.Conf) {
	// getting server info
	info, err := service.GetServerInfo(waitTimeout)
	if err != nil {
		log.Warnf("Cannot get service info (error: %s)", err)
		return
	}

	// registering device
	device := devicehive.NewDevice(config.DeviceID, config.DeviceName,
		devicehive.NewDeviceClass("go-gateway-class", "0.1"))
	device.Key = config.DeviceKey
	if len(config.NetworkName) != 0 || len(config.NetworkKey) != 0 {
		device.Network = devicehive.NewNetwork(config.NetworkName, config.NetworkKey)
		device.Network.Description = config.NetworkDesc
	}
	err = service.RegisterDevice(device, waitTimeout)
	if err != nil {
		log.Warnf("Cannot register device (error: %s)", err)
		return
	}

	// start polling commands
	listener, err := service.SubscribeCommands(device, info.Timestamp, waitTimeout)
	if err != nil {
		log.Warnf("Cannot subscribe commands (error: %s)")
		return
	}

	wrapper := DBusWrapper{service: service, device: device}
	exportDBusObject(bus, &wrapper)

	for {
		select {
		case cmd := <-listener.C:
			params := ""
			if cmd.Parameters != nil {
				buf, err := json.Marshal(cmd.Parameters)
				if err != nil {
					log.Warnf("Cannot generate JSON from parameters of command %+v (error: %s)", cmd, err)
					continue
				}
				params = string(buf)
			}
			log.Infof("COMMAND %s -> %s(%v)", config.URL, cmd.Name, params)
			bus.Emit(ComDevicehiveCloudPath, ComDevicehiveCloudIface+".CommandReceived", cmd.Id, cmd.Name, params)
		}

		//time.Sleep(5 * time.Second)
	}
}
Example #22
0
// Prepare GetDeviceList task
func (service *Service) prepareGetDeviceList(take, skip int) (task Task, err error) {
	// create request
	query := url.Values{}
	if take > 0 {
		query.Set("take", fmt.Sprintf("%d", take))
	}
	if skip > 0 {
		query.Set("skip", fmt.Sprintf("%d", skip))
	}
	url := fmt.Sprintf("%s/device", service.baseUrl)
	if len(query) != 0 {
		url += "?" + query.Encode()
	}

	task.request, err = http.NewRequest("GET", url, nil)
	if err != nil {
		log.Warnf("REST: failed to create /device/list request (error: %s)", err)
		return
	}

	// authorization
	service.prepareAuthorization(task.request, nil)

	return
}
Example #23
0
// NewService creates new service.
func NewService(baseUrl, accessKey string) (service *Service, err error) {
	log.Tracef("REST: creating service (url:%q)", baseUrl)
	service = &Service{accessKey: accessKey}

	// remove trailing slashes from URL
	for len(baseUrl) > 1 && strings.HasSuffix(baseUrl, "/") {
		baseUrl = baseUrl[0 : len(baseUrl)-1]
	}

	// parse URL
	service.baseUrl, err = url.Parse(baseUrl)
	if err != nil {
		log.Warnf("REST: failed to parse URL (error: %s)", err)
		return
	}

	// initialize HTTP client
	service.client = &http.Client{}
	// TODO: client.Transport
	// TODO: client.CookieJar
	// TODO: client.Timeout

	service.commandListeners = make(map[string]*core.CommandListener)
	service.notificationListeners = make(map[string]*core.NotificationListener)
	return
}
Example #24
0
// subscribe for notifications
func (service *Service) SubscribeNotifications(device *core.Device, timestamp string, timeout time.Duration) (listener *core.NotificationListener, err error) {
	if listener, ok := service.notificationListeners[device.Id]; ok {
		return listener, nil
	}

	// install new
	listener = core.NewNotificationListener()
	service.notificationListeners[device.Id] = listener

	go func(deviceId string) {
		log.Debugf("REST: start notification polling %q", deviceId)
		for {
			names := ""
			wait := "30"
			ntfs, err := service.PollNotifications(device, timestamp, names, wait, 60*time.Second)
			if err != nil {
				log.Warnf("REST: failed to poll notifications (error: %s)", err)
				// TODO: break? wait and try again?
			}
			if listener, ok := service.notificationListeners[deviceId]; ok {
				for _, ntf := range ntfs {
					log.Debugf("REST: got notification %s received", ntf)
					timestamp = ntf.Timestamp
					listener.C <- &ntf
				}
			} else {
				log.Debugf("REST: stop notification polling %q", deviceId)
				return // stop
			}
		}
	}(device.Id)

	return
}
// Process UpdateCommand task
func (service *Service) processUpdateCommand(task Task, command *core.Command) (err error) {
	// check task error first
	if task.err != nil {
		err = task.err
		return
	}

	// check status code
	if task.response.StatusCode < http.StatusOK ||
		task.response.StatusCode > http.StatusPartialContent {
		log.Warnf("REST: unexpected /command/update status %s",
			task.response.Status)
		err = fmt.Errorf("unexpected status: %s",
			task.response.Status)
		return
	}

	_ = command // unused
	// unmarshal
	//	err = json.Unmarshal(task.body, command)
	//	if err != nil {
	//		log.Warnf("REST: failed to parse /command/update body (error: %s)", err)
	//		return
	//	}

	return
}
Example #26
0
// subscribe for commands
func (service *Service) SubscribeCommands(device *core.Device, timestamp string, timeout time.Duration) (listener *core.CommandListener, err error) {
	if listener, ok := service.commandListeners[device.Id]; ok {
		return listener, nil
	}

	// install new
	listener = core.NewCommandListener()
	service.commandListeners[device.Id] = listener

	go func(deviceId string) {
		log.Debugf("REST: start command polling %q", deviceId)
		for {
			names := ""
			wait := "30"
			cmds, err := service.PollCommands(device, timestamp, names, wait, 60*time.Second)
			if err != nil {
				log.Warnf("REST: failed to poll commands (error: %s)", err)
				// TODO: break? wait and try again?
			}
			if listener, ok := service.commandListeners[deviceId]; ok {
				for _, cmd := range cmds {
					log.Debugf("REST: got command %s received", cmd)
					timestamp = cmd.Timestamp
					listener.C <- &cmd
				}
			} else {
				log.Debugf("REST: stop command polling %q", deviceId)
				return // stop
			}
		}
	}(device.Id)

	return
}
Example #27
0
// Prepare PollCommand task
func (service *Service) preparePollCommand(device *core.Device, timestamp, names, waitTimeout string) (task Task, err error) {
	// create request
	query := url.Values{}
	if len(timestamp) != 0 {
		query.Set("timestamp", timestamp)
	}
	if len(names) != 0 {
		query.Set("names", names)
	}
	if len(waitTimeout) != 0 {
		query.Set("waitTimeout", waitTimeout)
	}
	url := fmt.Sprintf("%s/device/%s/command/poll", service.baseUrl, device.Id)
	if len(query) != 0 {
		url += "?" + query.Encode()
	}

	task.request, err = http.NewRequest("GET", url, nil)
	if err != nil {
		log.Warnf("REST: failed to create /command/poll request (error: %s)", err)
		return
	}

	// authorization
	service.prepareAuthorization(task.request, device)

	return
}
Example #28
0
// send notification
// priority is ignored
func (w *DBusWrapper) SendNotification(name, parameters string, priority uint64) *dbus.Error {
	log.Infof("sending notification(name=%q, params=%q, priority=%d)", name, parameters, priority)
	dat, err := parseJSON(parameters)
	if err != nil {
		log.Warnf("failed to convert notification parameters to JSON (error: %s)", err)
		return newDHError(err.Error())
	}

	notification := devicehive.NewNotification(name, dat)
	err = w.service.InsertNotification(w.device, notification, waitTimeout)
	if err != nil {
		log.Warnf("failed to send notification (error: %s)", err)
		return newDHError(err.Error())
	}

	return nil // OK
}
Example #29
0
// NewService creates new Websocket /device service.
func NewService(baseUrl, accessKey string) (service *Service, err error) {
	log.Tracef("WS: creating service (url:%q)", baseUrl)
	service = &Service{accessKey: accessKey}

	// remove trailing slashes from URL
	for len(baseUrl) > 1 && strings.HasSuffix(baseUrl, "/") {
		baseUrl = baseUrl[0 : len(baseUrl)-1]
	}

	// parse URL
	service.baseUrl, err = url.Parse(baseUrl)
	if err != nil {
		log.Warnf("WS: failed to parse URL (error: %s)", err)
		service = nil
		return
	}

	// connect to /device endpoint
	ws_url := fmt.Sprintf("%s/device", service.baseUrl)
	headers := http.Header{}
	headers.Add("Origin", "http://localhost/")
	if len(service.accessKey) != 0 {
		headers.Add("Authorization", "Bearer "+service.accessKey)
	}
	service.conn, _, err = websocket.DefaultDialer.Dial(ws_url, headers)
	if err != nil {
		log.Warnf("WS: failed to dial (error: %s)", err)
		service = nil
		return
	}

	// set of active tasks
	service.tasks = make(map[uint64]*Task)

	// command listeners
	service.commandListeners = make(map[string]*core.CommandListener)

	// create TX channel
	service.tx = make(chan *Task)

	// and start RX/TX threads
	go service.doRX()
	go service.doTX()

	return
}
Example #30
0
// update command result
func (w *DBusWrapper) UpdateCommand(id uint64, status, result string) *dbus.Error {
	log.Infof("updating command(id:%d, status=%q, result:%q", id, status, result)
	dat, err := parseJSON(result)
	if err != nil {
		log.Warnf("failed to convert command result to JSON (error: %s)", err)
		return newDHError(err.Error())
	}

	command := devicehive.NewCommandResult(id, status, dat)
	err = w.service.UpdateCommand(w.device, command, waitTimeout)
	if err != nil {
		log.Warnf("failed to update command (error: %s)", err)
		return newDHError(err.Error())
	}

	return nil // OK
}