zettajs / zetta Goto Github PK
View Code? Open in Web Editor NEWAn API-first, open source software platform for the Internet of Things.
License: MIT License
An API-first, open source software platform for the Internet of Things.
License: MIT License
I created two versions of the hello-world
project by changing the port they listen on, ran both locally and linked them to the same hello-zetta.herokuapp.com
peer. According to hello-zetta.herokuapp.com
, only one peer is connected. Seems like the server that "wins" is whichever one was the last to come online.
To recreate:
https://github.com/zettajs/zetta-hello-world
to your local machineserver.js
to listen on a different port, like 2337
zetta-hello-world
to something else, like zetta-hello-world2
https://github.com/zettajs/zetta-hello-world
to your machine a second time/zetta-hello-world $ node server.js
/zetta-hello-world2 $ node server.js
Both servers peer to that same remote, but the remote only shows one of them. You can see that they're both running and streaming data by looking at how mangled the sinewave stream becomes:
In my LED driver code, I originally had:
.name('led ' + this.pin)
then I changed it to upper case:
.name('LED ' + this.pin)
But the names of the LEDs didn't change.
Because I was developing on the BeagleBone, I thought maybe I had opened the wrong file in the Cloud9 IDE or was doing something else wrong. After a while I gained confidence that I had changed the right file and that the new name was being ignored.
Eventually, I did rm -rf .peers .registry
because it had worked for me in the past. And it did again. The new names worked after doing the rm
.
When the pi or other local zetta instance restarts it shows connected to the cloud but the cloud does not see it as connected. I was able to reproduce the error a few times ~1/100 using my mac as a local zetta and a different heroku instance.
My heroku instance is using this branch https://github.com/zettajs/zetta/tree/peer-reconnect-issue
When the error happens I see the log on the local instance connected, on the cloud instance I see this websocket message. But none of the following messages for when the initial http request finishes or the peer registry adds it.
I also don't see any error on the http request here.
Any thoughts @kevinswiber @mdobson?
This will help minimize data over the wire. ETags are an HTTP caching mechanism. Weak ETags become invalid when the underlying representation is not semantically equivalent.
We can use transitions as a trigger for calculating new ETags. ETags should be calculated based on device properties and actions. If, even after a transition, both properties and actions are the same, the ETag value won't change and will still be valid.
Zetta should return 304 Not Modified
when receiving a request with an If-None-Match
header that has a value of a currently valid ETag. Otherwise, it should continue down the request pipeline.
Extra credit: Peers that proxy to other Zetta instanced could be proxying the transition log. In this case, we know when that ETag has potentially changed based on a transition firing. We can keep a record of the last valid ETag for the backend server's devices and return 304's on behalf of the backend server, limiting bandwidth usage and latency. We can also forward requests on when we know the ETag may have changed (based on a new transition coming in for that device).
In a device driver you should be able to pass an error to the callback and have http error with 500. It would also be nice if the body of the http response was the error message provided.
However currently the zetta instance throws.
LCD.prototype.change = function(message, cb) {
cb(new Error('some error message'));
};
Error output
Error: some message
at LCD.change (/Users/ApigeeCorporation/Software/zetta/zetta/sample/IHeardDat/devices/arduino/lcd_driver.js:23:6)
at Device.call (/Users/ApigeeCorporation/Software/zetta/zetta-device/device.js:119:39)
at run (/Users/ApigeeCorporation/Software/zetta/zetta/lib/api_resources/servers.js:137:17)
at /Users/ApigeeCorporation/Software/zetta/zetta/lib/api_resources/servers.js:92:12
at IncomingMessage.<anonymous> (/Users/ApigeeCorporation/Software/zetta/zetta/node_modules/argo/argo.js:100:7)
at IncomingMessage.emit (events.js:92:17)
at _stream_readable.js:938:16
at process._tickDomainCallback (node.js:463:13)
This seems to be the reason why it throws. https://github.com/zettajs/zetta-device/blob/master/device.js#L85
And this is not passing the errors along. https://github.com/zettajs/zetta-device/blob/master/device.js#L108
See mailing list email below.
Using the dot notation, I created a property called receivedSignalStrength for the FONA device that I'm modeling in Zetta.
When I called GET on the device's API:
GET /servers/beaglebone/devices/78c6200f-227b-4704-89c1-f54ad34153db
I was able to see the value in the properties object:
"receivedSignalStrength": "23"
Then I decided I'd also like to provide the ability for developers to monitor the value. So, I added:
config
.monitor('receivedSignalStrength');
However, once I added monitor(), the receivedSignalStrength value stopped appearing in the API GET request properties.
For a moment it looked like a one or the other choice: property or WebSocket.
But just for kicks I removed the peers and registry directories:
rm -rf ./peers ./registry
When I rebooted my server and hit the API, I saw receivedSignalStrength in the properties and as a WebSocket as I had hoped.
So, is this a bug? Which behavior is intended?
@mdobson @kevinswiber Starting an issue here to keep track of the findings.
Playing with it I'm noticing after reloading the browser a bunch of times it gets in the broken state. I added a console.log in the agents.socket.write function to inspect what's being sent over the socket. The last three times its got into the state i've noticed an 8 byte packet being constantly sent 20-30 times a second. The packet is formatted: [ 00 00 XX XX 01 00 00 00 ], XX XX being some type id that increments by two every packet.
Normally when a when a proxied http command is sent a packet is sent out I would see the normal http packet around 300 bytes being sent, followed by the same 8 byte packet, however only once per proxied request.
In wireshark it sees the packet a TCP segment.
We need to be able to extend the Zetta server. For instance, plugging into the HTTP pipeline is currently not doable.
What I'd like is something like this:
var zetta = require('zetta');
var OAuth = require('zetta-oauth');
var DataStore = require('.....');
zetta
.use(OAuth, DataStore)
.listen(3000);
Note that DataStore just represents an additional parameter that needs to get sent into the constructor of OAuth.
Perhaps the ServerExtension
class can have a list of abstract methods that, when implemented, help to plug into the HTTP pipeline at predefined locations.
It's great that I can see the id
of a device, but without the id
of the server I can't get at the device.
Does it make sense for the console log to include the id
of the server upon startup? Like it does with the device:
Oct-06-2014 18:21:38 [scout] Device (speech) 0cdcfd8b-c191-44e0-8b06-ad0cd6e9a1a1 was provisioned from registry.
Just wanted to document this issue. I have a feeling it will arise again. It appears that there is an async state weirdness with streams. Here is the sequence of events:
"data"
event"data"
event access the "artist"
property. It's out of sync.Can clarify tomorrow if this doesn't make sense. Just need it here so I don't forget.
var Device = require('zetta').Device;
var util = require('util');
var setTrack = function(self, calledFromTransition) {
self._sonos.currentTrack(function(err, track) {
if(err) {
return;
} else {
if((track && track.position > 0) || calledFromTransition) {
self.state = 'playing';
if(self.track !== track.title) {
//The track data event fires before the artist is set.
self.track = track.title;
self.artist = track.artist;
}
} else {
self.state = 'stopped';
self.track = '';
self.artist = '';
}
}
});
};
var setVolume = function(self) {
self._sonos.getVolume(function(e, volume) {
if(e) {
return;
} else {
if(volume) {
self.volume = volume;
}
}
});
};
var currentState = function(self) {
self._sonos.getCurrentState(function(err, state) {
self.state = state;
});
};
var SonosDriver = module.exports = function(sonos) {
Device.call(this);
this._sonos = sonos;
this._refreshInterval = null;
this.track = '';
this.artist = '';
this.volume = 0;
};
util.inherits(SonosDriver, Device);
SonosDriver.prototype.init = function(config) {
var self = this;
config
.state('stopped')
.type('sonos')
.name(this._sonos.host)
.when('playing', { allow: ['stop', 'skip', 'play-uri', 'play', 'volume-up', 'volume-down'] })
.when('stopped', { allow: 'play' })
.when('paused', { allow: 'play'})
.map('skip', this.skip)
.map('play', this.play)
.map('stop', this.stop)
.map('volume-up', this.volumeUp)
.map('volume-down', this.volumeDown)
.map('play-uri', this.playUri, [{ name:'endpoint', type:'url' }])
.monitor('artist')
.monitor('volume')
.monitor('track');
//poll the track every 3 seconds
self._refreshInterval = setInterval(setTrack, 1000, self, false);
//setTimeout(setTrack, 1000, self, false);
setTimeout(setVolume, 1000, self);
// setInterval(currentState, 1000, self);
};
SonosDriver.prototype.play = function(cb) {
var self = this;
this._sonos.play(function(e, playing) {
if(e) {
console.log(e);
if(cb) {
cb(e);
}
} else {
setTrack(self, true);
if(cb) {
cb();
}
}
});
};
SonosDriver.prototype.skip = function(cb) {
var self = this;
this._sonos.next(function(e, playing) {
if(e) {
console.log(e);
if(cb) {
cb(e);
}
} else {
setTrack(self, true);
if(cb) {
cb();
}
}
});
};
SonosDriver.prototype.stop = function(cb) {
var self = this;
this._sonos.stop(function(e, stopped) {
if(e) {
console.log(e);
if(cb) {
cb(e);
}
} else {
self.state = 'stopped';
self.track = '';
self.artist = '';
if(self._refreshInterval) {
clearInterval(self._refreshInterval);
}
if(cb) {
cb();
}
}
});
};
SonosDriver.prototype.playUri = function(url, cb) {
var self = this;
this._sonos.play(url, function(err, playing) {
if(err) {
console.log(err);
if(cb) {
cb(err);
}
} else {
setTrack(self, true);
if(cb) {
cb();
}
}
});
};
SonosDriver.prototype.volumeUp = function(cb) {
var self = this;
var newVolume = this.volume + 1;
if(newVolume > 100) {
newVolume = 100;
} else if(newVolume < 0) {
newVolume = 0;
}
this._sonos.setVolume(newVolume.toString(), function(e, data) {
if(e) {
if(cb) {
cb(e);
}
} else {
setVolume(self);
if(cb) {
cb();
}
}
});
};
SonosDriver.prototype.volumeDown = function(cb) {
var self = this;
var newVolume = this.volume - 1;
if(newVolume > 100) {
newVolume = 100;
} else if(newVolume < 0) {
newVolume = 0;
}
this._sonos.setVolume(newVolume.toString(), function(e, data) {
if(e) {
if(cb) {
cb(e);
}
} else {
setVolume(self);
if(cb) {
cb();
}
}
});
};
In app
module.exports = function(server) {
var sonosQuery = server.where({ type: 'sonos' });
server.observe(sonosQuery, function(sonos) {
sonos.streams.track.on('data', function(message) {
if(message.data !== '') {
console.log('Current track:', message.data);
//This statement will come back blank
console.log('Current artist:', sonos.artist);
}
});
});
};
It would be great to be able to suppress logs, or possibly hook into logs to allow users to pipe it to their desired log collector.
Not sure what causing the registry to fill up or create so many data files.
in my device driver, I had this:
config.type('text-to-speech');
in my app, I had this:
var speechToTextQuery = server.where({type: 'speech-to-text'});
when I fired up my server, Zetta just sat there. doing nothing.
it took me longer than I care to admit to track down the embarrassing mistake that I had made.
is there a creative way that Zetta could help me track down this kind of mistake more easily?
even a simple log of known queries and known devices back-to-back in the console might have helped?
I tried running Zetta on Windows Azure. It can run its own API just fine with connected devices. However, when trying to peer a local Zetta with Zetta on Azure, I got this error:
Sep-21-2014 16:06:41 [http_server] Websocket connection for peer c2a5eb39-1c51-43ad-a340-139891123f96 established
Sep-21-2014 16:06:46 [http_server] Websocket http request timed out for peer c2a5eb39-1c51-43ad-a340-139891123f96
Sep-21-2014 16:06:52 [http_server] Websocket http request timed out for peer c2a5eb39-1c51-43ad-a340-139891123f96
Sep-21-2014 16:06:57 [http_server] Websocket http request timed out for peer c2a5eb39-1c51-43ad-a340-139891123f96
2014-09-21T16:08:29 No new trace in the past 1 min(s).
Sep-21-2014 16:08:42 [http_server] Websocket connection for peer c2a5eb39-1c51-43ad-a340-139891123f96 established
Sep-21-2014 16:08:42 [http_server] Websocket connection for peer c2a5eb39-1c51-43ad-a340-139891123f96 established
Sep-21-2014 16:08:42 [http_server] Websocket connection for peer c2a5eb39-1c51-43ad-a340-139891123f96 established
Sep-21-2014 16:08:42 [http_server] Websocket connection for peer c2a5eb39-1c51-43ad-a340-139891123f96 established
Sep-21-2014 16:08:47 [http_server] Websocket http request timed out for peer c2a5eb39-1c51-43ad-a340-139891123f96
Sep-21-2014 16:08:47 [http_server] Websocket http request timed out for peer c2a5eb39-1c51-43ad-a340-139891123f96
Sep-21-2014 16:08:47 [http_server] Websocket http request timed out for peer c2a5eb39-1c51-43ad-a340-139891123f96
Sun Sep 21 2014 16:08:47 GMT+0000 (Coordinated Universal Time): Unaught exception: Error: write EPIPE
at errnoException (net.js:904:11)
at Socket._write (net.js:645:26)
at doWrite (_stream_writable.js:225:10)
at writeOrBuffer (_stream_writable.js:215:5)
at Socket.Writable.write (_stream_writable.js:182:11)
at Socket.write (net.js:615:40)
at Connection.write (D:\home\site\wwwroot\node_modules\zetta\node_modules\spdy\lib\spdy\connection.js:492:24)
at Scheduler.tickListener (D:\home\site\wwwroot\node_modules\zetta\node_modules\spdy\lib\spdy\scheduler.js:67:23)
at processImmediate [as _immediateCallback] (timers.js:345:15)
Application has thrown an uncaught exception and is terminated:
Error: write EPIPE
at errnoException (net.js:904:11)
at Socket._write (net.js:645:26)
at doWrite (_stream_writable.js:225:10)
at writeOrBuffer (_stream_writable.js:215:5)
at Socket.Writable.write (_stream_writable.js:182:11)
at Socket.write (net.js:615:40)
at Connection.write (D:\home\site\wwwroot\node_modules\zetta\node_modules\spdy\lib\spdy\connection.js:492:24)
at Scheduler.tickListener (D:\home\site\wwwroot\node_modules\zetta\node_modules\spdy\lib\spdy\scheduler.js:67:23)
at processImmediate [as _immediateCallback] (timers.js:345:15)
/cc @klevak
Currently, we have the ability to register devices over HTTP. What would an MQTT Scout look like? A TCP Scout? Should we make this extensible?
What's the best way to have a scout create a unique id for a device?
We entertained ideas ranging from including a query in the scout to having a .unique(hardwareId)
in the driver.
Confer with issue from Zetta Browser:
zettajs/zetta-browser#9
Ran into a strange issue building out demo code today. A monitored property is always returning null when trying to access it from it's getter.
module.exports = function(server) {
var sonosQuery = server.where({type: 'sonos'});
var twilioQuery = server.where({type: 'phone'});
server.observe([sonosQuery, twilioQuery], function(sonos, twilio) {
sonos.streams.state.on('data', function(message) {
if(message.data !== '') {
//sonos.artist always returns null
var sms = 'Sonos playing - ' + message.data + ' by ' + sonos.artist;
console.log(sms);
twilio.call('send-sms', '+17346345472', sms, function(err) {
if(err) {
server.log(err);
} else {
server.log('Sent your phone an update!');
}
});
}
});
});
};
I issued a POST without specifying content-type:
curl -X POST http://0.0.0.0:1337/servers/ba41550f-68f9-424d-b78e-123ee811014c/devices/0cdcfd8b-c191-44e0-8b06-ad0cd6e9a1a1
Zetta coughed up this error:
./node_modules/zetta/node_modules/argo-multiparty/index.js:5
nv.request.method === 'POST' && env.request.headers['content-type'].indexOf('m
^
TypeError: Cannot call method 'indexOf' of undefined
at null.<anonymous> (./node_modules/zetta/node_modules/argo-multiparty/index.js:5:77)
at b (domain.js:183:18)
at null.<anonymous> (./node_modules/zetta/node_modules/argo/node_modules/pipeworks/pipeworks.js:72:17)
at null.<anonymous> (./node_modules/zetta/node_modules/titan/node_modules/argo-formatter/formatter.js:48:7)
at b (domain.js:183:18)
at null.<anonymous> (./node_modules/zetta/node_modules/argo/node_modules/pipeworks/pipeworks.js:72:17)
at null.<anonymous> (./node_modules/zetta/node_modules/titan/node_modules/argo-url-helper/url.js:31:5)
at b (domain.js:183:18)
at null.<anonymous> (./node_modules/zetta/node_modules/argo/node_modules/pipeworks/pipeworks.js:72:17)
at null.<anonymous> (./node_modules/zetta/node_modules/titan/node_modules/argo-url-helper/url.js:31:5)
@mdobson @kevinswiber Starting a thread here for the issue we found yesterday. zetta.use() cannot determine if the first argument is a Device/Scout/App based on the base class's prototype if different versions of zetta-device
or zetta-scout
are installed for the device vs the base server.
Few options:
a: Don't use a ambiguous use call.
b: Change zetta-scout
and zetta-device
constructor to use a named function like:
var Device = module.exports = function Device(){};
Then compare on the constructors name Device or Scout. However this has issues with zetta versions not matching.
c: Add some other property to Device/Scout that could distinguish it, possibly with a version associated with it. Seems more hackish.
d: Use npm peerDependencies. Biggest downside to this options is that it may be unnatural for module developers that are not familiar with Dependencies.
Any thoughts on opening up logging in the server file as well? We have it every where else basically.
var zetta = require('zetta');
var LED = require('./');
var server = zetta()
.use(LED)
.listen(1337, function(err) {
server.log('Error:', err);
});
or
var zetta = require('zetta');
var LED = require('./');
zetta()
.use(LED)
.listen(1337, function(err) {
this.log('Error:', err);
});
Hey I'm going through and building a small API consumer app before the conference, and just making notes of things that I observe when building. I'd like to add a server relation to all the peer links in addition to the peer relation. I think it would make it easier for a client to access all the relevant servers quickly with this relation in place. Thoughts?
{
"class": [
"root"
],
"links": [
{
"rel": [
"self"
],
"href": "http://zetta-cloud-2.herokuapp.com/"
},
{
"title": "cloud",
"rel": [
"http://rels.zettajs.io/server"
],
"href": "http://zetta-cloud-2.herokuapp.com/servers/2d72035a-fff5-4183-a4da-ca6001706b76"
},
{
"title": "matt.dobson",
"rel": [
"http://rels.zettajs.io/peer",
"http://rels.zettajs.io/server"
],
"href": "http://zetta-cloud-2.herokuapp.com/servers/5961a387-44ee-4e8a-8d88-9791fcb6b0fc"
},
{
"title": "Detroit",
"rel": [
"http://rels.zettajs.io/peer",
"http://rels.zettajs.io/server"
],
"href": "http://zetta-cloud-2.herokuapp.com/servers/d23094cf-aba5-4c7b-b3ee-b43807ce4e95"
},
{
"rel": [
"http://rels.zettajs.io/peer-management"
],
"href": "http://zetta-cloud-2.herokuapp.com/peer-management"
}
]
}
I issued a POST with empty data:
curl --data "" http://0.0.0.0:1337/servers/4c16ef80-c4a3-4990-9f6b-7a05f17ed37a/devices/0cdcfd8b-c191-44e0-8b06-ad0cd6e9a1a1
Zetta coughed up this error:
./examples/node_modules/zetta/lib/api_resources/servers.js:103
body = querystring.parse(body.toString());
^
TypeError: Cannot call method 'toString' of undefined
at ./examples/node_modules/zetta/lib/api_resources/servers.js:103:37
at IncomingMessage.<anonymous> (./examples/node_modules/zetta/node_modules/argo/argo.js:100:7)
at IncomingMessage.EventEmitter.emit (events.js:92:17)
at _stream_readable.js:920:16
at process._tickDomainCallback (node.js:459:13)
Hey All,
Did a deep dive into a bug @alanguir was running into earlier today. We thought it was medea hint files, but that was really a red herring. It was an issue with a double use()
call of a driver. Check out the server code here: https://github.com/alanguir/zetta-button-app/blob/master/server.js
Here is the scenario that I believe is happening:
"Camera"
"Lights"
"button"
applyArgs
by putting the registry data object as the first item using unshift()
"button"
device properlyprovision
we typically chop off the first data object argument and send off the other arguments (A constructor function, and additional arguments) to the scientist for creationThe offending piece of code can be found here:
https://github.com/zettajs/zetta-auto-scout/blob/master/auto_scout.js#L41-L44
A small hack to fix this is below. If we shift off the data object after we call provision everything will be provisioned properly.
results.forEach(function(result) {
applyArgs.unshift(result);
self.provision.apply(self, applyArgs);
applyArgs.shift();
});
However, there is a second issue as well. Since we filter on the type of device in the registry we actually call each provision of button with a single auto scout instance and it's corresponding argument. Which means the arguments in the second device use()
call is ignored. Basically this means that we provision a "Camera"
"button"
and a "Lights"
"button"
with the following statement .use(Button, "Lights")
This is a weird issue and properly an incoherent writeup. I can repro monday morning and talk through it more as well.
Queries via the API use saved registry data, making it impossible to query on in-memory state.
Here is an interesting issue. The following code won't do what we think it would do. It will just sit there doing nothing. Should we investigate doing a patch on this part of the API to handle this scenario?
var zetta = require('zetta');
var inst = zetta()
.name('mdobs')
.listen(1337, function(err) {
if(!err) {
inst.link('http://hello-zetta.herokuapp.com/');
}
});
This work around will remedy the issue, but doesn't account for the peer cleanup process which is another internal function.
var inst = zetta()
.name('mdobs')
.listen(1337, function(err) {
inst.link('http://hello-zetta.herokuapp.com/');
inst._initPeers(function(err) {
if(err) {
console.log(err);
}
});
});
We need to be able to have control over the subscription created by Runtime#observe. This will allow us to dispose of the subscription if needed.
would be nice if Zetta had log levels to help with grep
on output
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
I created a new state machine via copy and paste from another driver's state machine. But when I went to run it I wasn't seeing the states that I had created. after much staring at code, I realized that I had never deleted the original off
and on
states at the very end of the state machine. code below.
would Zetta help me by flagging duplicate state entries?
.when('off', { allow: ['turn-on', 'turn-on-pulse', 'turn-on-alternating', 'flash']})
.when('on', { allow: ['turn-off', 'turn-on-pulse', 'turn-on-alternating', 'flash'] })
.when('pulse', { allow: ['turn-off', 'turn-on', 'turn-on-alternating', 'flash'] })
.when('alternating', { allow: ['turn-off', 'turn-on', 'turn-on-pulse', 'flash'] })
.when('flash', { allow: [] })
.when('off', { allow: ['turn-on'] })
.when('on', { allow: ['turn-off'] })
This will allow us to compose observables in apps.
Currently, to create a new read stream on a device, we do something like:
heartbeat.streams.pulse.on('data', function(pulse) {
// do something with pulse
});
We have a custom getter on streams
that creates a new readable stream with each property access.
This gets confusing.
heartbeat.streams.pulse.on('data', function(pulse) {
// do something with pulse
});
heartbeat.streams.pulse.on('error', function(err) {
// this is an error handler on a different stream!
});
See the issue?
I'd like to be more explicit about stream creation.
Something like...
var pulseStream = heartbeat.createReadStream('pulse');
pulseStream.on('data', function(pulse) {
// do something with pulse
});
pulseStream.on('error', function(err) {
// this is an error handler on a different stream!
});
Thoughts?
/cc @AdamMagaluk @mdobson
Hey Dudes,
Been working on my sonos driver. Adding a callback to the init function like within the Scout init may be advantageous for some pre configuration. Using the Sonos lib everything is async, and so retrieving any relevant info is a PITA.
//this._sonos => JS interface to sonos.
SonosDriver.prototype.init = function(config, cb) {
config
.state('online')
.type('sonos')
.name(this._sonos.host);
this._sonos.currentTrack(function(err, track) {
if(!err && track) {
config
.state('playing')
self.track = track.title;
cb(); //Hey we're done configuring. Wire up device.
}
});
};
When a peer disconnects and reconnects several times, it reconnects multiple times. This is causing errors.
it would be nice to have a more intuitive way to find all devices that know about specific properties, like temperature. something like:
where properties include temperature
Tooling with some cli stuff. Would be nice to see Zetta queries in an interface to figure out what is going on in the system.
Could help solve issue #75 as well.
Need to decode transition arguments based on the type in the field object. This isn't currently being done.
Please provide link to documentation. I have visited http://www.zettajs.org/ however couldn't find proper documentation there.
I want to do POC to connect Andruino robot through zetta platform.
Thanks,
Purvish
I was following the Home Security project. When I ran node server.js
the first time I got the error below.
The fix was to rm -rf .peers/ .registry/
# node server.js
error: Failed to find devicetree fragment: bspwm_P9_14_6
info: 0: 54:PF---
1: 55:PF---
2: 56:PF---
3: 57:PF---
4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
7: ff:P-O-L Override Board Name,00A0,Override Manuf,am33xx_pwm
info: Error loading devicetree overlay for P9_14 using template bspwm
error: error updating PWM freq and value: undefined, Error: ENOENT, no such file or directory 'undefined/duty'
Yet, the device and server sent messages to the console as if all was good.
Apr-23-2014 20:30:35 [scout] Device (buzzer) 8c01a134-43b3-4c44-a2d0-8226df5f7901 was discovered
Zetta is running at http://beaglebone.local:1337
We broke Windows support when we created hidden directories (prefixed with a ".").
Let's use underscores instead of periods on Windows (common convention).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.