Homey Community Forum

JSON problem

I cant use JSON on the usualy way. I have a problem with the following code:

if (inJSON != "") {        
        var each;
        for (each in inJSON)
        {
          this.log(each);
          if (each == 'sensors') {
           // this.log(inJSON[each]);
            this.log(inJSON['sensors']);  // this line is working
          }
        }
        this.log(inJSON['sensors']);  // this line throws error: TypeError: Cannot read property 'sensors' of undefined
      }

there is two same line, but only the first is workingā€¦ :frowning:
Any idea?

Where is inJSON coming from? The issue is the context in which your code is running, not the code itself.

Does it matter? In that point (where it throws the error), if I just print the JSON out to the console, there is no problem.
This is just a simplified example code to find, and show the problemā€¦

No, it doesnā€™t. I rewrote your simplified example to test it:

const inJSON = { foo: 'bar', sensors : 'xxx' };

this.log = console.log;

if (inJSON != "") {        
  var each;
  for (each in inJSON)
  {
    this.log(each);
    if (each == 'sensors') {
      // this.log(inJSON[each]);
      this.log(inJSON['sensors']);  // this line is working
    }
  }
  this.log(inJSON['sensors']);  // this line throws error: TypeError: Cannot read property 'sensors' of undefined
}

This works just fine. Like I said, your issue is not with this code but with the context in which it is used.

ok. here is my full app.js.
It connects to myIO server, and ask a JSON (inJSON) (first, with descriprions, after that a faster same JSON, without descriptions) in the setInterval(). This is a string, parsing to JSON ), and refreshing the server_data variable (it is a JSON).
My problem is, I canā€™t reach this JSON from the driver.js and from the device.jsā€¦ (I tried it many ways)
So if the server_data is refreshedā€¦ it is set to the settingsā€¦ (homey.settings.set(ā€˜server_dataā€™, server_data):wink:
And I can red that from other .js filesā€¦ so it is working nowā€¦ but a example at the end is throwing the errorā€¦

'use strict';

const Homey = require('homey');
const { createSecureContext } = require('tls');
var XMLHttpRequest = require('xhr2');
var server_data;

class myIO_App extends Homey.App {

  /**
   * onInit is called when the app is initialized.
   */
  async onInit() {
    
    var inJSON;
    var _responseTXT;
    var string2send;
    var updated_settings;

    // get settings variables
    var defaultSettings = this.homey.settings.get('defaultSettings');
    var address = this.homey.settings.get('address');
    var http_port = this.homey.settings.get('http_port');
    var app_port = this.homey.settings.get('app_port');
    var username = this.homey.settings.get('username');
    var password = this.homey.settings.get('password');
    
    // if it is the first time to start app, fill the settings with default variables
    if (defaultSettings == null) {
      this.homey.settings.set('address', '192.168.1.170');
      this.homey.settings.set('http_port', '80');
      this.homey.settings.set('app_port', '843');
      this.homey.settings.set('username', 'admin');
      this.homey.settings.set('password', 'admin');
      this.homey.settings.set('defaultSettings', 'set');
    }    
    
    this.homey.settings.set('updated_settings', 'true');    // set this from the index.htm to true
    this.homey.settings.set('server_data', "");

    // refreshing the server_data JSON
    setInterval(() => {                                 
      
      updated_settings = this.homey.settings.get('updated_settings');

      if (updated_settings == 'true') {                   //if index.html changed the settings or first turn
        this.homey.settings.set('server_data', "");
        address = this.homey.settings.get('address');
        http_port = this.homey.settings.get('http_port');
        app_port = this.homey.settings.get('app_port');
        username = this.homey.settings.get('username');
        password = this.homey.settings.get('password');
        //log settings variables
        this.log(address+" "+http_port+" "+app_port+" "+username+" "+password);
        string2send = "/d_sens_out.json";
        this.log("Settings_updated");
        this.homey.settings.set('updated_settings', 'false');
      } else {
        string2send = "/sens_out.json";
      }

      //this.log('Try to connect to myIO server');

      var request = new XMLHttpRequest();
      request.open('POST', "http://" + address + ":" + http_port + string2send, true);
      var enc = Buffer.from(username + ":" + password).toString('base64');
      request.setRequestHeader("Authorization", "Basic " + enc);
      var _tempThis = this;             // because I will need it in the next function.
      request.onload = function () {       
        _responseTXT = this.responseText;        
        try {
          inJSON = JSON.parse(_responseTXT);          
          if (string2send == "/d_sens_out.json"|| server_data==null || server_data=="") {
            server_data = JSON.parse(JSON.stringify(inJSON));
          } else if (server_data!=null && server_data!=""){
            
            var key, number, element;
            for (key in inJSON) {
              if (key == 'relays') {
                for (number = 0; number < Object.keys(inJSON[key]).length; number++ ) {
                  for (element in inJSON[key][number]) {
                    server_data[key][number][element] = inJSON[key][number][element];                      
                  }                    
                }
              }          
            }            
          }          
          console.log("succesfull server_data update: " + server_data['relays'][0]['state']);
          _tempThis.homey.settings.set('server_data', server_data);
        }
        catch (e) {
          console.log("JSON parse error: "+e);        
        }        
      };
      // this is just a simple example to show the anomaly
      if (inJSON != "") {        
        var each;
        for (each in inJSON)
        {
          this.log(each);
          if (each == 'sensors') {
            this.log(inJSON[each]);
            this.log(inJSON['sensors']);  // this line is working
          }
        }
        this.log(inJSON['sensors']);  // this line throws error: TypeError: Cannot read property 'sensors' of undefined
      }

          try {
            request.send();
            console.log("request ok.");
          } catch (e) {
            console.log("request error: " + e);
          }          
    }, 5000);

    
    
    this.log('MyApp has been initialized');
  }  
  
}


module.exports = myIO_App;

The location of your example code is outside the (asynchronous) onload handler. Only inside the onload handler can you be sure that inJSON is initialized.

To make your life easier, I would suggest dropping XMLHttpRequest (which is a browser API anyway) and use a Promise-based module for HTTP requests, like http.min:

const http = require('http.min');
ā€¦
try {
  const inJSON = await http.post({
    uri:     "http://" + address + ":" + http_port + string2send,
    json:    true,
    headers: {
      authorization: 'Basic ' + Buffer.from(username + ":" + password).toString('base64')
    }
  });
  ...
} catch(e) {
  console.log('HTTP request error', e);
}

thank you! I will change it.

Unfortunately, I cant make it work :frowning:
it has something problem with the await ā€¦

SyntaxError: await is only valid in async function

But if I delete the await, it has more other problemsā€¦ :frowning:
my code is:

'use strict';

const Homey = require('homey');
const { createSecureContext } = require('tls');
var XMLHttpRequest = require('xhr2');
var server_data;
const http = require('http.min');

class myIO_App extends Homey.App {

  /**
   * onInit is called when the app is initialized.
   */
  async onInit() {
    
    //var inJSON;
    //var _responseTXT;
    var string2send;
    var updated_settings;

    // get settings variables
    var defaultSettings = this.homey.settings.get('defaultSettings');
    var address = this.homey.settings.get('address');
    var http_port = this.homey.settings.get('http_port');
    var app_port = this.homey.settings.get('app_port');
    var username = this.homey.settings.get('username');
    var password = this.homey.settings.get('password');
    
    // if it is the first time to start app, fill the settings with default variables
    if (defaultSettings == null) {
      this.homey.settings.set('address', '192.168.1.170');
      this.homey.settings.set('http_port', '80');
      this.homey.settings.set('app_port', '843');
      this.homey.settings.set('username', 'admin');
      this.homey.settings.set('password', 'admin');
      this.homey.settings.set('defaultSettings', 'set');
    }    
    
    this.homey.settings.set('updated_settings', 'true');    // set this from the index.htm to true
    this.homey.settings.set('server_data', "");

    // refreshing the server_data JSON
    setInterval(() => {                                 
      
      updated_settings = this.homey.settings.get('updated_settings');

      if (updated_settings == 'true') {                   //if index.html changed the settings or first turn
        this.homey.settings.set('server_data', "");
        address = this.homey.settings.get('address');
        http_port = this.homey.settings.get('http_port');
        app_port = this.homey.settings.get('app_port');
        username = this.homey.settings.get('username');
        password = this.homey.settings.get('password');
        //log settings variables
        this.log(address+" "+http_port+" "+app_port+" "+username+" "+password);
        string2send = "/d_sens_out.json";
        this.log("Settings_updated");
        this.homey.settings.set('updated_settings', 'false');
      } else {
        string2send = "/sens_out.json";
      }

      try {
        const inJSON = http.post({
          uri:     "http://" + address + ":" + http_port + string2send,
          json:    true,
          headers: {
            authorization: 'Basic ' + Buffer.from(username + ":" + password).toString('base64')
          }
        });
       
        if (string2send == "/d_sens_out.json"|| server_data==null || server_data=="") {
          server_data = JSON.parse(JSON.stringify(inJSON));
        } else if (server_data!=null && server_data!=""){
          var key, number, element;
          for (key in inJSON) {
              for (number = 0; number < Object.keys(inJSON[key]).length; number++ ) {
                for (element in inJSON[key][number]) {
                  server_data[key][number][element] = inJSON[key][number][element];                      
                }                    
              }       
          }            
        } 
        if (server_data != null && server_data != "") {
          console.log("succesfull server_data update: " + server_data['relays'][0]['description'] + " : " + server_data['relays'][0]['state']);
          console.log("succesfull server_data update: " + server_data['PWM'][0]['description'] + " : " + server_data['PWM'][0]['state']);
          this.homey.settings.set('server_data', server_data);
        }
      } catch(e) {
        console.log('HTTP request error', e);
      }
    }, 5000);

  
    
    this.log('myIO_App has been initialized');
  }  
  
}


module.exports = myIO_App;

Try
setInterval(async() => {

1 Like

it seems working :slight_smile: Thank You very much!

1 Like