This forum is a read-only archive. Posting, accounts and search are no longer available.
1 / 84
Nov 2015

This topic is opened for discussing the implementation of a simplified hardwareinterfaces API.
Goal is to allow a user to:

  • Use the API for implementing ideas in javascropt/node.js directly.
  • allow an easy way to program adapters for other hardware then the Arduino Yun

Yes
I think if we have all of these constructors at the beginning of the server.js helps to keep the overview.

It’s maybe a bit confusing.
The server follows a push concept.

In the beginning the server looks through all available hardware interfaces and calls exports.receive one time from the server.js to start (in the Arduino case) a serialServer with a callback.
Whenever there is data coming in within the serialServer the callback triggers the objectEngine() in the server.js file. This is what I thought could be replaced with listenIO(). writeIOToServer() might be a better description.

When the objectEngine() processes a link that points to the serialServer then exports.send is triggered. This is what I thought about being writeIO(). IODataFromServer from server might be a better description.

Because of syncing the Arduino Atmega with the Server there are a couple of possitions in the Server.js that calls exports.init this tells the arduino library that the server is fully loaded and ready to run the initialization process.

To make the init resulting processes more clear I think we can split them in to:

addIO() would add the name of a new ObjectValue in to a buffer.

clearIO() would do a couple of things:

  1. check if the buffered ObjectValue name is present in the server.
    If it exist keep it with its state, if not add a new one.
  2. delete all ObjectValue that are not in the addIO() name buffer
  3. clear the name buffer.
  4. check that all links are valid.

developerIO()
activate or deactivate the developer functionality.

Well I’m running into a problem when running the object code from github. I installed the code on a Yun and didn’t change anything. But when i run “node server.js” it crashes:

Loading template: documentation
developer
add
I will save: yun2Test and: led id: 0
add
I will save: yun2Test and: generator id: 1
clear
------del---

/mnt/sda1/HybridObjects/hardwareInterfaces/arduinoYun/index.js:299
            for (var key in objectExp[objectID].objectValues) {
                                               ^
TypeError: Cannot read property 'objectValues' of undefined
    at clearIO (/mnt/sda1/HybridObjects/hardwareInterfaces/arduinoYun/index.js:299:48)
    at SerialPort.<anonymous> (/mnt/sda1/HybridObjects/hardwareInterfaces/arduinoYun/index.js:256:21)
    at SerialPort.emit (events.js:95:17)
    at /usr/lib/node_modules/serialport/parsers.js:25:17
    at Array.forEach (native)
    at Object.parser (/usr/lib/node_modules/serialport/parsers.js:24:13)
    at Object.SerialPort.options.dataCallback (/usr/lib/node_modules/serialport/serialport.js:149:15)
    at SerialPortFactory.SerialPort._emitData (/usr/lib/node_modules/serialport/serialport.js:320:20)
    at afterRead (/usr/lib/node_modules/serialport/serialport.js:296:20)
    at /usr/lib/node_modules/serialport/serialport.js:312:9

I’ve added one HybridObject via the webinterface and uploaded the readWrite sketch. It’s a little bit weird because when the “add add clear” sequence runs first immediately after uploading the sketch it works and I can’t figure out what’s different the following times. I can’t see how “objectExp[objectID]” could become “undefined”

Ah ok, it seems that for some reason in server.js the callback of

templateModule.loadAllModules(modulesList, function () {
    // start system
    if (globalVariables.debug) console.log("Starting System: ");
    loadHybridObjects();
    startSystem();

});

is never executed on my setup so objectExp never gets initialized.

EDIT: It seems like the template loading happens asynchronously so that the loadAllModules function immediately returns, am I right?

This is an interesting behavior. It must have slipped in when marcteys added a new developer fronted.
I think it is good to not make the server dependent on (or encapsulated) the asynchronous startup of the developer frontend. I just had a quick check and it seems the server and the frontend work with not having

loadHybridObjects();
startSystem();

encapsulated as a callback. But I have no Yun until monday to test the data monitoring part.
I just send marcteys an email if he can join the conversation about it.

Yes, that’s what I did then, just moved the two functions outside. Seems to work so far…

Ok, I’ve started to implement the API. I forked the project to: GitHub - Carsten87/object: Hybrid Objects code 14

I added a new file: libraries/HybridObjectsHardwareInterfaces and moved all the interface code there. The following functions are implemented so far:

  1. writeIOToServer()
  2. addIO()
  3. clearIO() (didn’t change that, still missing the link checking)
  4. developerIO()

Additionally I removed loadHybridObjects() and startSystem() from the callback as mentioned above.

I also started to implement a hardwareInterface for Philips Hue. It’s not much use yet, still missing vital parts, the exports.send() part is not yet implemented and so far the onOff state is the only IO Point. But it’s already using the newly implemented functions. So it might be good to look at it to see how to use them.

What I plan to do next:

  • Add some comments
  • extend the functionality of the PhilipsHue hardwareInterface
  • test it all

P.S. I would love to get some feedback and I’m open to suggestions :wink:

UPDATE
I cleaned up the API and removed the passthrough parameters from the functions. I added the setup() function which initalizes the references to those parameters and is called once in server.js. So the parameters don’t need to be passed to the functions anymore and are hidden from the API user.

UPDATE2
I’m now using the new API functions in the yun hardware interface. But I can’t test it all right now, I will do that somewhen this week and tell you if it’s working :slight_smile:

And I’ve come up with some more questions:

  1. Even if I don’t add it, I always get a “test” IO point in my HybridObjects. At least it appears on the WebFrontend and produces random values. What’s that about?
  2. What exactly is the init() function supposed to do? It’s called three times from server.js so it cannot be used to put some setup stuff in there which should only run once, right?

Sounds very good. I am looking forward to see the progress and your comments. I have time later this week for it.

Have you checked if your Arduino still has a “test” object uploaded. You can create new objects by simply adding them in the arduino code. You can also run the server.js from your computer. The server will then ignore the YunInterface. Is the test object still showing up when you run it from your computer?

init() asks the arduino library to run the setup communication with the server. It is placed at multiple locations, to guarantee synchronization. It is possible that some of these calls are not needed. I will have a closer look at it later this week as well.

@valentin The “test” IO point appears in every HybridObject I create, be it a “arduinoYun” or “philipsHue” HybridObject. It does not appear in an objects objectValues though (at least not when clearIO() is called, that’s when I checked). That’s why I suspect it is just added to the GUI at some point. But I didn’t have the time yet to really look into it.

@Carsten Maybe this one helps: Can you comment the lines 243 to 247 in the file HybridObjectsWebFrontend.js and see if it still comes up?

jsonVariables.push({
   "test": infoCount,
   "value" : "test",
   "IOName" : d.getMilliseconds()
});

OK, I’ve tested it and I’ve found some small bugs which I already fixed. I couldn’t test the yunInterface so far (maybe next week) but with the philipsHue interface it works fine.

The only things I deem to be quite ugly are the index and amount variables in addIO() and clearIO(). Isn’t the index only used in clearIO()? Or did I overlook it somewhere else? Instead of the amount variable the user could pass the ioNames of the IO points he wishes to keep. I think that would be more understandable. What do you think?

My updated TODOS:

  • add comments
  • add some error handling to the philipsHue interface
  • add some more functionality to the philipsHue interface
  • get rid of index and amount (maybe, depending on your input)
  • test the yunInterface

index and amount are relevant for communicating with the arduino library.

Index is used to keep a reference to the numerical index in the arduino array, independent from the js object “index” position (which can change).
It helps to minimize the SerialData traffic to just sending numbers.

By initializing the object, the server checks if a IOpoint with the added index exists.
If the name is identical it keeps the IOpoint and its data. If not, the IOpoint is deleted and a new IOpoint with the index is added.

To clear the objectValues, the arduino library sends the amount of IOpoints the server can count with.
The server deletes all IOpoints with a bigger index.

This is all done so that the existing values associated with the IOpoints are not overwritten every time the server restarts.

Because all the appearance of the IOpoint in the GUI and all relevant data about the IOpoint is saved in the objectValues and in a file on disk for the next program start, you need to keep track what is already existing the moment you run the initialization. Otherwise your GUI will reset with every start.

We can move the amount and index code in to the ArduinoYun interface. It is very specific and should not be in a generalized API.
I had a lookup table for the index before. We can bring this idea back. The lookup table simply keeps track of the arduino numerical index associated with the objectValues name index.
This will allow to remove the index from the objectValues and all the routines outside of the ArduinoYun hardware interface.

Never the less, the API should have some code to keep track what IOpoints are used, if they existed before and which IOpoints are obsolet and can be deleted.

Yes that’s exactly what I thought. So I can remove the index from the addIO() function and move the index management to the yun interface. At the moment clearIO() basically gets the amount and removes every IOpoint with an index greater or equal to amount. What I thought is that instead of passing the amount you could pass the names of the IOpoints and remove any IOpoints with names different than the ones passed. The effect would be the same but the function would be easier to use/understand I think.

Exactly, this would be the better solution.

Ok, I have implemented the stuff described above. But while experimenting around i realized that it is no good to have a global clear variable because every hardware interface only knows its own state and not the state of other hardware interfaces so setting this variable can have undesired effects. I think you don’t really need the clear variable at all. You should just call clearIO() after the addIO() calls and that’s it. Or am I missing something?

It’s similar with the developer variable. Because it has a global impact I’m not sure if it should be set in a hardwareInterface. Theoretically the developer of one hardwareInterface could set developer to true and the developer of another could set it to false and in the end it would be set to the value which was defined in the last hardwareInterface loaded. That’s sort of random. But on the other hand I have no clue where else to put it…

The hardware interface has to describe in every ObjectValue where the provided value comes from.
This is relevant for the routing when data is processed.

For example the values from the Yun interface indicate “arduinoYun”

Line 165:   
ObjectValue = function () {
        ...
        this.type = "arduinoYun";
    }

When the server processes an incoming link, that has a destination value with the type “arduinoYun” it knows that it needs to be processed with the ArduinoYun hardware interface.
The Philips Hue probably would indicate to be the “philipsHue”

  • We can call clearIO(“interfaceName”) within the hardwareInterface after all addIO()'s have been called. The clearIO function would then only process values that contain the indicated type.

  • The developer variable has to be set from within the hardwareInterfaces so that it can be controlled from everywhere. But the model can be like this: It is on by default and will be switched off if a developer wants it. This way you can change the developer mode from within arduino and you never need to touch the server code.

We should also think about a smart way how we can indicate if an interface is in use or not.
We could drop not used ones from the folder, but maybe it makes more sense to set a switch within the file.
What do you think?

I think a switch would be the simplest solution. Something like:

exports.enabled = true;

So if I got it right you want to give the API user the means to disable the developer mode but not to enable it?

We can call clearIO(“interfaceName”) within the hardwareInterface after all addIO()'s have been called. The clearIO function would then only process values that contain the indicated type.

I think we could create a data structure to which addio() writes the io points it just added. Cleario() could then use this data structure to compare against the io points restored from the file system.

Ok, now I am creating a bit of a confusion. I think I had an error in the thoughts from before.
I think the developer mode should be disabled by default and the API user has to set a variable to true for enabling it.

Good Idea

Agree

I will also help down the road to document the server and the editor code much much better.

Yes, that’s already on my TODO list. I will do that after I have implemented the few changes mentioned above. Probably will get it all done today or early next week.

Ok, I think I’m almost done. Still missing the comments though :-). I ran into one small issue. The webServer checks if globalVariables.developer is set before it can be changed by any hardwareInterface. If it isn’t set, the Web GUI doesn’t start. So I think that we should let the user either just set the developer and debug variables directly in server.js or we could create some kind of config file and load the values from there. In the API we would then just provide getters.

And I haven’t tested it all thoroughly yet. So if you find some bugs, let me know…

EDIT: I have started to add some comments. I will add some more to the empty example and the philipsHue interface next week. I’m not really into this licensing stuff, so what shall I put on top of the files I created/modified? And you probably might want to cross read since I’m not a native speaker and might have produced some grammatical mistakes :wink:

I can have a look later at the webserver part so that it responds “in time”.
The arduino hardwareInterface needs to have this functionality.

The server is put under the Mozilla open source license.
For the files that you have created you can write in to them:


Created by YourName on Date.
Copyright (c) 2015 YourName

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 Mozilla Public License, version 2.0.


For files that you have made changes to, you can add underneath the created line the following:

Modified by YourName on Date.

No worries,
As long as the idea is understandable, it should be fine.

Ok, I can see, how legacy programs using the arduino c++ libraries developer() function might depend on it. But nonetheless it would be more logical to set a global variable globally in some config file. I think to overcome this problem and maintain backwards compatibility in the arduino hardwareInterface when the developer command is received at

        case 40:
            if (parseInt(data, 10) === 1) {
                globalVariables.developer = true;
            }
            else {
                globalVariables.developer = false;
            }
            dataSwitch = 0;
            break;

we could simply do nothing like:

    case 40:
        dataSwitch = 0;
        break;

And remove the developer command from future versions of the arduino c++ library. In my opinion that would be a better solution.

I think it’s a good idea to store the developer value in a config file.
It should be part of the object.json file where all objects are stored.
It’s a bit ugly programmed right now, because all objects have a developer value already and
I used the heartbeat loop to sync the object with the globalVariables.developer in the server.js line 458.
It is used to communicate to the Reality Editor if the developer mode for a particular object should be displayed.
This allows the user to move GUI elements around.

Maybe we can drop the global variable and continue with the object owned only.
This one is stored on disk (object.json) with any major change to the objects and loaded on program start.
Then the only question remains how does the developer web-GUI response as a whole?

There was a specific functionality I thought of, when adding the developer mode:
One should be able to build a project with only Arduino (or other external tools) and some web know how.
It was mend for If one wants to expose the project to others in some way and prevent that someone can temper around with the object. Its relevant since every Reality Editor has a developer mode switch. For simplicity reasons, it is meaningful that the arduino developer can stop the object within the Arduino code from exposing the developer services.

If one will have a ready to go object and that person only just learned Arduino, this would be the only way with his know how level to access this control. If we have it somewhere in the server, it creates a big entry barrier.

How about:

   case 40:
            if (parseInt(data, 10) === 1) {
                developerOn();
            }
            else {
                developerOff();
            }
            dataSwitch = 0;
            break;

Ah OK now I get it. I somehow overlooked the object’s developer flag. I thought there was only the global one :blush: So yes I agree with you we should drop the global flag for the objects and use the local ones instead. I think for the webinterface we should just introduce another global flag which the developer can set. Do you think we should let the developer set the global debug and the new webdeveloper flag directly in server.js or should we rather move that to a new config file?

I will implement it tomorrow I think.

EDIT
I now created the developerOn(objName) and developerOff(objName) functions which can turn on/off the developer mode for the specified HybridObject. Problem with the arduino hardware interface is that the objName is not passed on by the c++ librarie’s developer() function but this information is vital if we want to enable the developer flag to be switched per HybridObject. So someone has to change that library and we will have to think of something if we want to be backwards compatible with the current library. Of course we would have to modify the yun Hardware interface to handle the additional input from the c++ library as well.

Temporary workaround for now is that the developer() calls are ignored in the yun hardware interface and objectExp.developer is set to true by default.

Additionally I replaced the global developer flag with a webdeveloper flag which can be used to enable/disable the web GUI.

And I will be able to test it somewhen next week. So no guarantees that it works :smile:

I think we are making things more complicated then they have been before!
I do not see any advantage of two separate developer modes and a flag for every individual object. It creates the potential for human error. Therefore we should go with the following solution improving the old model:

  1. The global and object specific developer mode is always false by default.
  2. Whenever developerOn() is called, the global developer flag as well all existing objects will be set to true.
  3. The add() function need to check back with the global developer flag in case developerOn() is called earlier.
  4. The web server is checking for the global developer flag every time the developer functions are being accessed. If global developer flag is still false, the server responds with a general overview of the object.

This way we make sure that an object is always started in a user mode and only intensionally set to developer mode.

Ok, makes sense to me. What is important with this model is, that we don’t have a developerOff() function, I think. Because if we had one, the behavior could become undeterministic. Imagine the developer calling developerOn() in one hardwareInterface and developerOff() in another. There is no way for the developer to determine which function is called first so it would be completely random if the developer functions are turned on or off in the end.

Points one to three should be easy to implement. I haven’t really looked into the web server code yet, so point four might take a while and we would have to determine what information to show. Maybe it would be better/faster if you implemented point four @valentin ?

Exactly, with this model we do not need developerOff().
I remember that I spend some time on point 4 before and that it was once implemented this way.
I will check if this is still the case and adjust if needed.

Ok, I implemented point 2 and 3. Didn’t set the global developer flag to false by default though. I will wait with that until point 4 is implemented.

As before I couldn’t really test it yet because I don’t have an iOS device at home. So I couldn’t check if all works as expected with the Reality Editor. I will be able to test it somewhen next week.

This thread is a good read, glad to see the H/W interface abstraction!

@Carsten, I’ll be experimenting with your fork, and I do have an iOS device so I’ll try to kick the tires on the developer setting mods you made, if I can get the Pi running.

To get started on the pi you can just install it like @V_Mohammed_Ibrahim did. To get it working with the gpio pins fast you could take a look at https://www.npmjs.com/package/rpi-gpio or https://www.npmjs.com/package/pi-gpio. Looks like it could work out of the box. So you don’t really have to wait until the python bridge is finished because it seems you can address the gpio pins directly from nodejs/Javascript.

Let me know if you run into any issues with the hardware interface @KevinOrtman

Hi Carsten, I have merged your work on the hardwareInterface in to a beta_hardwareInterfaces branch.
I have some time on the weekend for debugging and adding the functionality we discussed with the point 4.

Thanks, @Carsten the work you did on the hw interface is great! I’m waiting on some hardware to arrive (a GPIO breakout board for my Pi, and a brand new Yun).

Once I have that in hand, I’ll start tinkering with the I/O. I plan on using JS to interface, so I’ll base my stuff on the work that you and @valentin put into place for the Yun/Hue.

Thanks for the lib references as well. Looks like https://www.npmjs.com/package/onoff 1 might also be a good choice - it had more monthly downloads than the other two combined & appears to support BeagleBone GPIO in addition to the Pi.

  • Thoughts?
27 days later

Continuing the discussion from the Real Time monitoring error thread.

I created a new branch Bugfix_reinit 2 where I moved the addIO() and clearIO() calls to the exports.init() function for each hardware interface. init() is now called the first time immediately before receive() is called. I tested it for all HW interfaces except arduinoYun and raspberryPi. Before we merge the branch into the beta_hardwareinterfaces branch it would be good to test those two as well. Maybe you could help with that @valentin and @V_Mohammed_Ibrahim ?
Testcase is as follows:

  1. Add some I/O points for the respective hardware interface.
  2. Go to the configuration dashboard.
  3. Add a target.
  4. Do not restart the server.
  5. Check that everything works as expected (Especially check that the I/O points are shown in the Reality Editor)
  6. If you want to do the test again delete the files from the objects folder
8 days later

Hello,
Start experiencing OpenHybrid, and the hardware interface. Sounds Good.
In particular looking at slider example: it seems little bit CPU expensive. So I’m looking for an improvement.
In fact I think, a pretty smart implementation would to send to /object/value, on each change on IO point (in writeIOtoServer).
So the continuous reading in Realty editor for changing values becomes not necessary.
Unfortunately, no access is possible for a socket.emit in writeIOtoServer.

What do you think of this suggestion ?
Other to do that ?

On which side do you see the CPU intensity?

The Server only reacts on events. This means for the time that there is no input change, the CPU should not be used very much.
You should write your code in such a way, that you only write to the server, if there is actually a data change.

From the Reality Editor side:
I can see that maybe a subscription model with pushed data would be working as well.
This can be up for discussion. However, the request model works for now and provides a simple interface for multiple devices.
What do you think?

Hi Valentin,

its a bit exaggerated for CPU activity: just for this slider exemple, we have when no activity on the phone, a request for info each 50 milliseconds.

Yes i think push model or event oriented sounds better at me, some eventEmitter could help around server.js .

For my understanding, the interface part (index.html and javascript files) run on the reality editor, i m right ?

I like very much your project.

Franck

Yes I think you have very good point.
It would be much less intensive if the Server would just push its data to the Editor.
But for that case, we would need to set subscription method for what kind of data should be send to the Editor.

Would you like contributing to it?

Yes that is right.
Its loaded as an iFrame in to the Editor and the iFrame is 3D-Transformed.
You can think about it basically as a regular webpage loaded in to a browser.

One thing to take care of:
The iFrame is created and the content is loaded in to it, once the object/marker becomes visible.
Once the object/marker is not visible anymore, the Editor waits for 3 seconds if it comes back and then removes the iFrame with the web content from the DOM.

This means that your CPU intensive webpage only pulls data for the amount of time the object is visible.

I agree. Maybe we could use the onload and onunload events. I’m not sure if and when they are triggered in an iFrame but it might be just what we need. If the events are triggered as expected - which should be tested first :wink: - we could put the subscription into onload and the unsubscription into the onunload part. In server.js we could then send the data to the reality editor whenever objectEngine() is called. What do you think?

@Carsten I think thats how it should be.
If its not working we can add the subscription to the library instance HybridObject() to be called one time.
I remember that the onload function can only be loaded one time. We would block it if a user decide to use it.
Maybe I am wrong.

If there is no onunload method, we could kill the subscription once socket.io declares the connection as broken/dead. Socket.io provides a couple of infos about the connection that are useful.

What I like a lot about this idea is, that we get rid of some extra timings in the javascript code exposed to a developer.

@valentin You are right. Instead of onload/onunload we should rather use the socket information. I’m not familiar with socket.io but isn’t it possible for the socket.io server to keep track of the connected clients? So the client could subscribe to the server when the connect event triggers and pass the information the server needs (objectID?) to send data to the client. When the server notices that the client has disconnected it just stops sending data.

Hi,
What is the primray branch to start development ?

  • beta hardware new interface
  • or Bugfix reinit.

Thx.
I will first try something: I will add winston framework for logging, a more configurable one. I hope you (@Carsten or @valentin, i don’t who is the integrarot in fact :smiley:) will merge it.

@franck @valentin I would suggest that we create a new topic branch, branching from beta_hardwareInterface since the changes proposed have nothing to do with the purpose of the Bugfix_reinit branch.

@Carsten exactly.
socketUpdater() is doing such a check already.
We can simple check the bool <ourSocket>.io.connected.

However, the socketUpdater() is created to keep the sockets alive at any cost.
We would need to include special handling for GUI connections.

I am not quite sure, how to implement the subscription out of the box and I will not have much time to help this next two weeks as I am preparing/running a Hybrid Object design workshop.
Have you done something like that before?

If someone has to much time, we can also extend the socketUpdater() to check if an object has been missing for some time (this is the case, when socket.io connection can not be established for like a minute or so) and temporary deactivate links to that object. The deactivated links could be written in objectLinksDeactivated = {}. Once that link is available again, the links can be copied back. If the links can not be reestablished for 3 days, they should be killed entirely. This would solve a major GUI bug, which renders the GUI useless, if links to not reachable objects exist.

Fork done, i started something, logging for the moment to undestand the code :wink:. Is it possible to test interface in browser? it fails for me when i click on index.html (partial exchange with the server)

I update a pull request, i had a version that push event to websocket… so no polling is needed now.

@Carsten I did a first test with two Arduino boards.

What works:

  1. The server load fully in the Arduino Yun.
  2. The objects are loaded from JSON file.
  3. New Objects are well created via Arduino IDE. This means that the init procedure works.
  4. IO-Points within the same Object can be connected rightfully.
  5. The Objects show up rightfully in the Editor and GUI communicates rightfully with the Server.
  6. Arduino can write values to the Server.

What does not work:

  1. The Server can not write Values to the Arduino.
    I just committed a small fix: Now an index is send via Serial instead of a JS Object.
    It should work now, but it does not. :smiley: This needs more debugging (I can do this after the Workshop next week).
  2. When IO-Points are connected between two Hybrid Objects, no data get received.
    I remember that there where some changes in the objectEngine, afterPluginProcessing, SocketSender or SocketServer that seemed odd to me at the time. The error must be in the decision whether the data is processed internally or externally or in the right format of the message @Carsten could you look at the Socket connection in comparison to version 0.3.1? You can test this with two computers running each a server.

@franck I have not much time next week to look through all the code changes you made, but it is possible that your code inherit some of the problems above (2). Maybe you can help to debug the Socket connection from Server to Server?

@valentin Thx for testing.
I never noticed issue (2) because I’m currently running everything on one server instance. I will look into that problem. I think I might even have caused it, because I messed with the content passed to objectEngine at some point.

UPDATE:
OK, i fixed the bug (2). The socketSender was sending wrong data. I fixed it in the beta_hardwareInterfaces branch and also merged it into the Bugfix_reinit branch. This seems to have solved the realtime monitoring error as well :slight_smile:

I think the problems has something to do with inconsistent ID handling:
https://github.com/openhybrid/object/blob/beta_hardwareInterfaces/server.js 5

L1351 pos and obj should not be mixed in to one objID at this point.
If I remember right,
the pos or value-ID or objID or IO-Point-ID (we need to call all this IDs that name the same thing just IOPoint in the code) is created in the moment the IO-Point is initialized. From that moment on it can be used as ID (thats what msgContent.pos points to). The code seems to generate obj+pos, where pos represents already obj+pos.
The rest of the code should just use the ID consistently.
In general I think it is good to let the object engine handle what ever ID is given instead of generating them on the spot.
L1359 the formatting seems wrong (check against v0.3.1)
L1362 obj and pos are added together, where it should not be. (check against v0.3.1)
L1371 format is wrong. (check against v0.3.1)
L1490 format is wrong. (check against v0.3.1)

It seems like the IDs are mixed up here and there and a consistent handling through out the code is not happening. We should check this against v0.3.1 so that the final IDs used for data socket connections match between v0.3.1 and the new version.

It’s all a little bit confusing,

When you say format is wrong you are not quite right. The lines you are referring to (L1359, L1371, L1490) call a hardware interface’s exports.send() function. I changed the signature so that the hardware interface developer only has to deal with the names of the objects and IO points. I don’t pass the id’s anymore. That totally makes sense.

msgContent.pos is always only the name of a IO point. That is what is send by the UI’s object.js write() function. So socketSender() has to send the name of the IO point as well because this format needs to be consistent since it is sent to the same server. Befor I fixed it socketSender() did send an id.

When a link is created by the RealityEditor its locationInA / locationInB is set as IOName + ObjID which is why obj and pos are added together in L1362.

Well I can only say it works now and it makes sense (at least to me :wink: ) It’s a little bit difficult to explain though.

Hemm. I know. Its a bit of a head wrapping around it.
When I am back in Cambridge I can help with debuging.

Ah, I just understood something I think:

This if statement https://github.com/openhybrid/object/blob/v0.3.1/server.js#L1309 1 basically checks if the message comes from the UI via write() which only sends the name of the IO point as pos or if it comes from the socketSender() which sends the id of the IO point as pos. If the socketSender() would also send only the name which my fix does now, one branch of the if becomes obsolete and could be removed. But that would mean older versions (like 0.3.1) which send the id would no longer be able to communicate with a newer server.

Personally I think it would be clearer if socketSender() and write() would send in the same format and there was no if statement. But that means we would lose backwards compatibility.

Ahh yes.
I think in the first versions each IOPoint was created with an IOPointName+UUID.
Then I changed it for the Arduino to objectId+IOPointName.
The reason was to minimize the string length saved for each point in the Arduino.
This allowed to always load the same object and IDs.
Making such a strong change might be actually needed.

I belive that it actually is still compatible with the older version.
Because as long as it handles incoming IDs and outgoing IDs the same, the other Object should not have an issue handling it.
I believe that only the object ID has a constrain with 12 UUID chars at the end.

Ok, now the socketSender() is only sending the IOPointName but the socketServer() still accepts both formats. I committed it into the Bugfix_reinit branch.

Well yes, as long as we keep the part in socketServer() which accepts IOPointName + objectID it will be compatible with the older version.

Maybe i can help. What is the socket from server to server ? i don’t how to configure this case. 2 OpenHybryd server, and how you connect to each other. I investigate soon

@franck I think I already fixed it, but you are welcome to test. You just have to run the code of Bugfix_reinit on two different physical machines, create a HybridObject on each and connect IOPoints of the two objects with each other.

Ok, I found the time and something to connect to the gpio pins to debug the raspberryPI hardwareInterface myself. Seems to work. I merged the Bugfix_reinit branch into the beta_hardwareInterfaces Branch.

The only thing that is not working so far is the issue Valentin discovered:

Because I don’t have a Yun anymore I won’t be able to debug that one.

11 days later

I’ve got an idea for an extension of the HardwareInterfaces API and would like to hear your opinions:

I’ve found myself wanting to exchange more complex data between the WebUI and the associated HybridObject. It’s not very handy to do that via “invisible” IOPoints or something. For example if you take a Radio and you want to display the currently playing song in the WebUI, how do you do that? Obviously you don’t want to expose that information as an IOPoint. So I thought, we could easily use socket.io for that. It’s already available on both sides. We could either create a new socket server on a different port or somehow use the existing one on port 8080. I didn’t think about implementation details like how to direct messages to the right hardware interface and what new API functions would be necessary yet. It’s just a raw idea at this point. Any thoughts?

16 days later

I think this is a good idea.
But we need to be very careful designing it.

For one I think invisible IOPoints are a necessary feature. We need them to communicate IO Signals that are only for the Web Interface but not for the programming.

I think we can add a text value for each IO Point. This would not be any complex addition.
We can simply create a new data type called “t” and handle it with the given infrastructure.

I think it would be good to create a detailed document on what data types are possible.
We need to keep it compact and organized.

What do you think @Carsten?

I think, invisible IOPoints have several downsides:

  1. They are not really invisible. They have got to have a name which is rendered as caption in the RealityEditor.
  2. You have to poll them. Probably @franck has fixed that, we should definitely look at this soon.
  3. I find them counter-intuitive. It’s sort of a breach of concept.

That’s why I thought about creating another separate communication channel between the HybridObject and the Web Interface solely for the purpose of communicating stuff you don’t want to expose as an IOPoint without any restrictions with regards to datatypes.

And yes a detailed document on what data types are possible is a very good idea :slight_smile:

This is something that I can easily be fixed in the editor code.

I know. I definitely want to spend 3-4 days just to review all the code that we have lie around by now.

I am not sure, lets discuss a bit more. I would say that hidden IO-Points are good for easy learnability, because the IO-Points guarantee that you can reference data throughout the entire code and all platforms via “object” and “location” within the object. This would make it simpel to understand.
If we open another data connection, this would mean that you would need to learn an entire new system.
With hidden IO-Points you just need to add the attribute hidden to what is already known. It makes it more simple.

I would agree that it does not make sense to have these invisible data as part of the processing engine… Maybe we can exclude them from the overall processing? And this is where you probably think that it is counter-intuitive? You might have a complete different method of interaction in mind? Can you write more about why it is counter-intuitive?

Maybe we can pass messages with another name then “object” to the server.
We could call them “interface” and as such they could be accessible in the server?

But if we find an intuitive method that can be modelt with what we have and we build up on it, it would make the learning curve for a new developer much smaller.

Yes, exactly. IOPoints are supposed to be connected to each other and they are restricted to be of a certain datatype. In contrast to that what I had in mind is a means of communication ONLY between the HybridObject and the WebUI where you are not restricted to a specific datatype. This means you can’t connect the HybridObject communication endpoint to anything else but the WebUI communication endpoint but you can pass arbitrary data (JSON objects, strings or whatever)

I think it is a little bit confusing if you mix up those two ways of communication. Because for IOPoints you say they can only be float values, but then you suddenly make an exception and say that for “hidden” IOPoints everything is allowed. That seems inconsistent to me.

And as you said, the invisible data doesn’t need to part of the processing engine. Basically all you need is a socket connection between HybridObject and WebUI so that whenever a value on either side changes the other side can react to it accordingly, there is no need to handle links because there can’t be any.

Yes, I like that idea and it’s basically what I had in mind.

@Carsten Now I understand it much better and agree.
I had the same issue before and its a good solution.

1 year later