Digi Device API reading Datastream / DIO / AD

435 views Asked by At

I have XBee Gateway ZB, Wifi and I'm experimenting with the Digi Device API. I already tried the Heroku App xbeegateway.herokuapp.com and it works really good.

So I wanted to access online the Datastream. Using Google Spreadsheet or something like this. So reading the documentation from digi. I could acces the Gateway through http://devicecloud.digi.com/ws/DataStream/00000000-00000000-00######-########/xbee.serialIn/

But that's not the problem. I thought that I could see the serialIn that I send via Arduino to the Gateway. (I'm sending a string which contains the temperature of my room.) But looking at the xml I can't really understand it.

<result>
<resultSize>1</resultSize>
<requestedSize>1000</requestedSize>
<pageCursor>94a9cb44-1-cb91b9c6</pageCursor>
<DataStream>
<cstId>9921</cstId>
<streamId>
00000000-00000000-00######-########/xbee.serialIn/[00:##:##:00:##:##:##:##]!
</streamId>
<dataType>STRING</dataType>
<forwardTo/>
<currentValue>
<id>230fee58-158b-11e5-a4a7-fa163eefb35b</id>
<timestamp>1434612303755</timestamp>
<timestampISO>2015-06-18T07:25:03.755Z</timestampISO>
<serverTimestamp>1434612304781</serverTimestamp>
<serverTimestampISO>2015-06-18T07:25:04.781Z</serverTimestampISO>
<data>TWVzc3VuZzogMjIgQ2Vsc2l1cw0K</data>
<description/>
<quality>0</quality>
</currentValue>
<description/>
<units/>
<dataTtl>2678400</dataTtl>
<rollupTtl>2678400</rollupTtl>
</DataStream>
</result>

I see the Timestamp but I can't understand what this should mean <data>TWVzc3VuZzogMjIgQ2Vsc2l1cw0K</data>. Is it kind of character code or did I misunderstand something?

If I look in JavaScript in Heroku App at the Serial Terminal Widget I get this code. It looks like it's using var decoded = utils.base64_decode(newData);.

/*
 * This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
 * obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2014 Digi International Inc., All Rights Reserved.
 */

'use strict';

angular.module('XBeeGatewayApp')
    //jshint -W098
    .controller('serialWidgetCtrl', function ($scope, utils, $log, dashboardApi, notificationService) {
        $scope.data_sending = false;
        $scope.last_received_timestamp = undefined;

        $scope.getStreamUpdateHandler = function (newData) {
            // For the serial widget, data *should* come in as an object of the form
            //   {"content": "...", "format": "base64"}
            var _newData = newData.value;
            if (_.isEmpty(_newData)) {
                $log.warn("Serial widget got malformed data", newData);
                return;
            }
            var _timestamp = newData.timestamp;
            newData = _newData;

            // XBee Gateway
            if (angular.isString(newData)) {
                var decoded = utils.base64_decode(newData);

                if (_.isEmpty(decoded)) {
                    // Might not be decoded.
                    newText = newData;
                } else {
                    // Successfully decoded the data.
                    newText = decoded;
                }
                $log.info("Adding text:", newText);
                $scope.displaySerialText(newText, true);
                $scope.last_received_timestamp = _timestamp;
                return;
            }
            // Or, XBee Wi-Fi
            else if (newData.content !== undefined){
                // Check format to see if we should b64 decode
                var newText;
                if(newData.format === "base64"){
                    newText = utils.base64_decode(newData.content);
                } else {
                    newText = newData.content;
                }
                $scope.displaySerialText(newText, true);
                $scope.last_received_timestamp = _timestamp;
            } else {
                // TODO display some error?
                $log.warn('Serial widget got malformed data', newData);
            }
        }

        $scope.setStreamUpdateHandler = function (newData) {
            // Updates to the set stream could be handled here too, as we use the same for get/set
            return;
        }

        $scope.serialEnterKeypress = function($event){
            if($scope.serialOutText){
               $scope.sendText($scope.serialOutText);
            }
            $event.preventDefault();
        }

        $scope.sendText = function(text) {
            $scope.data_sending = true;

            if ($scope.widget.add_carriage_returns) {
                // Insert a CR before/after string to make it show on new line
                // on both ends
                var cr = String.fromCharCode(13);
                text = cr + text + cr;
            }

            dashboardApi.send_serial($scope.widget.device, $scope.widget.radio, text).then(
                function(result){
                    // On success, show the sent text
                    $scope.displaySerialText(text, false);
                    // Clear the input box for next entry
                    $scope.serialOutText = null;
                    // Reenable input
                    $scope.data_sending = false;
                },
                function(reason){
                    notificationService.error("Error sending text. Please try again.");
                    // Reenable input
                    $scope.data_sending = false;
                });
        }

        $scope.$watch('data_sending', function (sending) {
            if (sending) {
                $scope.widgetState = 1;
            } else {
                $scope.widgetState = 0;
            }
        });
    })
    .directive('serialWidget', function (widgetRegistry, utils, dataStreams, $log) {
        // called after DOM element is compiled
        var linker = function postLink(scope, element) {
            scope.$element = element;
            var type = 'serial';
            var spec = widgetRegistry.get(type);

            // See http://lodash.com/docs#bind
            // (dataUpdate simply calls scope.updateHandler)
            var getCallback = _.bind(scope.getStreamUpdateHandler, scope);
            var setCallback = _.bind(scope.setStreamUpdateHandler, scope);
            utils.postlinkWidget(type, scope, element, spec, getCallback, setCallback);
            // Any more fancy footwork can be done here.

            // Manually listen for serialIn
            var device = scope.widget.device;
            var inputStream = "xbee.serialIn/[" + scope.widget.radio + "]!";
            $log.debug("Listening for serial stream: ", device, inputStream);
            var removeListener = dataStreams.listen(device, inputStream, scope.getStreamUpdateHandler);
            scope.$on('$destroy', function () {
                removeListener();
            });

            // Widget display area
            // Use jquery to find, Angular's jqlite doesn't support selector
            var output_pane = $(element).find(".serial-display");

            scope.displaySerialText = function(text, isInbound){
                var $newText = null;
                if(isInbound){
                    $newText = $('<span/>').addClass("serial-in");
                    // Show incomming text inline
                    // Split string to handle any Carriage Returns
                    if(text === "\r"){
                        $newText.append($('<br>'));
                    } else {
                        var snippets = text.split("\r");
                        _.each(snippets, function (snippet) {
                            // CR at start & end will make cause empty strings
                            if(snippet === ""){
                                $newText.append($('<br>'));
                            } else {
                                $newText.append($('<span/>').text(snippet));
                            }
                        });
                    }
                } else {
                    // Outgoing should be in it's own line
                    $newText = $('<p/>').text(text).addClass("serial-out");
                }
                $(output_pane).append($newText);
                $(output_pane).scrollTop($(output_pane)[0].scrollHeight);
            }
        };

        // AngularJS directive setup
        return {
            templateUrl: "widgets/serialWidget/serialWidget.tpl.html",
            restrict: 'AE',
            link: linker,
            controller: 'serialWidgetCtrl',
            scope: { widget: "=serialWidget", widgetState: "=state" }
        };
    })
    // This function, referred to in AngularJS as a "run block", is called by
    // AngularJS after the injector is created and is used to bootstrap the
    // application. The XBee ZigBee Cloud Kit makes use of the run block
    // to add widget definitions to the widget registry at start-up.
    .run(function(widgetRegistry) {
        // Adding the widget to the widget registry
        var widget_type_key = 'serial';
        var widget_description = 'Serial Data Widget';
        var widget_spec = {
            // Whether or not the widget is built-in or user-created
            // (i.e., whether the code is in /src/app or /src/common)
            builtin: true,
            // widget size: X,Y (columns, rows)
            size: [3, 2],
            // description appearing in 'Widget Type' list when adding new
            // widgets
            description: widget_description,
            directive: "serial-widget",
            // camel-case version of directive
            directive_c: "serialWidget",

            // properties pertaining to widget settings
            /*
            has_input: does the widget's data get updated from Device Cloud?
            sends_output: does the widget send data to the device?
            input_xform: can the user specify a custom transformation to apply
                            to incoming data? (optional)
            options: list of objects defining the settings associated with this
                        widget type
                - options generally follow the Revalidator API
                    (http://github.com/flatiron/revalidator)
            */
            has_input: false,
            sends_output: false,
            options: [
                {key: "add_carriage_returns", label: "Add Carriage Returns",
                 type: "boolean", required: false, 'default': true}
            ]
        };

        // DO NOT CHANGE ANY CODE BELOW HERE.
        widgetRegistry.put(widget_type_key, widget_spec);
    });
2

There are 2 answers

0
Steinfeld On BEST ANSWER

Okay my bad. Never heard of base64. Maybe because I'm new to online data streaming.

After searching I found a site that use base64 decode: https://www.base64decode.org

I could decode TWVzc3VuZzogMjIgQ2Vsc2l1cw0K.

1
Victor Macias On

No you need to change the option enable encode 64 or not enable encode 64 into the digi Gateway,

Regards Victor