Closed BrianGenisio closed 9 years ago
At first I had thought that this shield had a unifying I2C interface, but the more I read it, I realize that is not the case. Really, there are two chips just connected to the I2C bus:
So, in reality, the devices should be for these chips specifically:
var humidity = new five.Humidity({
controller: "HTU21D"
});
var temperature = new five.Temperature({
controller: "HTU21D"
});
We can alias them as PHOTON_WEATHER_SHIELD
to beef up the user experience... but really, this is all it is.
For new five.Temperature({ controller: PHOTON_WEATHER_SHIELD'})
, we'll have to decide which temperature reading to take. It is probably an arbitrary decision, but I'd probably go for HTU21D, because that is the one that is called out for having Temperature in the product on the website.
There are lots of altimeter and humidity components that are commercially available, so let's go ahead and create two new component classes:
Other Multi breakouts:
* The existing Barometer
class can also be aliased as Pressure
, if we think that will be intuitive.
Hi ,
Waou ! Thanks for this information. I will take a look .
Vesuviian
Le 30 sept. 2015 à 15:52, Rick Waldron notifications@github.com a écrit :
There are lots of altimeter and humidity components that are commercially available, so let's go ahead and create two new component classes:
Altimeter BMP180 (implemented, just need to expose data) MS5607 can be implemented add more... Hygrometer (I don't mind if we also export an alias called Humidity *) SHT15 RHT03 via I2C backpack add more... Other Multi breakouts:
BME280
- The existing Barometer class can also be aliased as Pressure, if we think that will be intuitive.
— Reply to this email directly or view it on GitHub https://github.com/rwaldron/johnny-five/issues/912#issuecomment-144407965.
The Photon weather shield is fairly expandable, with built in ports for wind and rain sensors, and pin-outs labeled for soil moisture, soil temp and more. I thin focusing on the specific devices on the shield (HTU21D, MPL3115A2) is probably the right decision. This also means you won't have to make a decision about which temperature to use for the controller.
Cool. I just ordered the AdaFruit standalone version of those two sensors so I can test them separately. I'll be hacking a bit tomorrow, so if the shield shows up, I might have some good progress to show.
I was looking through some of my stuff and I found the SparkFun Weather Shield for Arduino (https://www.sparkfun.com/products/12081). It has the same humidity and barometer sensors as the SparkFun Weather Shield for Photon - plus it has a ALS-PT19 light sensor. This confirms for me that the controllers should be the sensor ID (i.e. HTU21D, MPL3115A2, ALS-PT19).
Making progress on the HTU21D support here: https://github.com/BrianGenisio/johnny-five/tree/photon-weather-shield
I'm able to get relative humidity and temperature, but I can't seem to get them both at the same time. I need to toggle between reading the temperature register and the humidity register using i2cReadOnce
but the act of toggling makes the values unreliable. If I hold the register the same, then I can read the values successfully, but when I toggle, the values are bad.
I think it must be some sort of timing bug... not sure what it is, though. I'm going to move on to the MPL3115A2 to clear my brain. #cc @dougseven
This is the code I'm using to test. I didn't check it into the J5 repo because it is an example using the photon:
var five = require("johnny-five");
var Particle = require("particle-io");
var board = new five.Board({
io: new Particle({
token: process.env.PARTICLE_TOKEN,
deviceId: process.env.PARTICLE_DEVICE_ID
})
});
board.on("ready", function() {
var temperature = new five.Temperature({
controller: "HTU21D"
});
var hygrometer = new five.Hygrometer({
controller: "HTU21D"
});
temperature.on("change", function() {
console.log("temperature");
console.log(" fahrenheit : ", this.fahrenheit);
console.log("--------------------------------------");
});
hygrometer.on("change", function() {
console.log("humidity");
console.log(" relative humidity : " + this.relativeHumidity + "%");
console.log("--------------------------------------");
});
});
Why would you create two objects using the HTU21D controller? Couldn't you just create one that exposes properties for each of the data types: var hygrometer = new five.Hygrometer({ controller: "HTU21D" });
hygrometer.on("change", function() { console.log("temperature"); console.log(" fahrenheit : ", this.fahrenheit); console.log("humidity"); console.log(" relative humidity : " + this.relativeHumidity + "%"); console.log("--------------------------------------"); });
Why would you create two objects using the HTU21D controller? Couldn't you just create one that exposes properties for each of the data types:
Because temperature readings are the exclusive domain of the Temperature class. Once @BrianGenisio is done, he will wrap all of these in an instance of the Multi
class that exposes each of the single purpose sensor objects as properties. Take a look at IMU. I also just realized that I need to write up docs for Multi
That makes sense. How will the Multi class handle the fact that there are two temperature values - one from each sensor. From a usage standpoint I have seen people take the values from each and average them to account for any variances.
var temp = (hygrometer.F + barometer.F) / 2;
is this an example of what the implementation would look like?
var weather = new five.IMU({
controller: "PHOTON_WEATHER_SHIELD"
});
// hF, hC, bF, bC are holder variables for the fahrenheit and celsius values from the
// hygrometer and barometer respectively.
var hF, hC, bF, bC, relativeHumidity, pressure;
weather.on("data", function() {
hF = this.hygrometer.temperature.fahrenheit;
hC = this.hygrometer.temperature.celsius;
bF = this.barometer.temperature.fahrenheit;
bC = this.barometer.temperature.celsius;
relativeHumidity = this.relativeHumidity;
pressure = this.pressure;
});
var fahrenheit = (hF + bF)/2;
var celsius = (hC + bC)/2
This is the example I am building for our workshop to use the Photon Weather Shield. Since I am working on the documentation and samples in parallel to @BrianGenisio and @rwaldron I want to verify that this is correct (I have made some assumptions here).
https://github.com/dougseven/Demos/blob/master/photon/IoTHub/weather.js
is this an example of what the implementation would look like?
Close... There are actually two different "multiple sensor modules" on this shield and I'm not sure how to resolve the competing temperature sensors to consolidate the two into one. We've been around the block re: "shields as a class" and it always comes up short.
Yours has asynchrony problems. This:
var fahrenheit = (hF + bF)/2;
var celsius = (hC + bC)/2
...will execute only once, and before any code inside the "data" handler is ever executed.
https://github.com/dougseven/Demos/blob/master/photon/IoTHub/weather.js
With the exception of the temperature
properties appearing on instances of classes that they don't exist on, this makes sense.
That makes sense. How will the Multi class handle the fact that there are two temperature values - one from each sensor. From a usage standpoint I have seen people take the values from each and average them to account for any variances.
var temp = (hygrometer.F + barometer.F) / 2;
Meh. It might be time to revisit an older argument discussion about Shield
...
If each of the sensors (Multi) in the shield has its own temperature, why wouldn't you make temperature a property of the Mulit sensor within the shield?
hC = this.hygrometer.temperature.celsius;
bF = this.barometer.temperature.fahrenheit;
relativeHumidity = this.hygrometer.relativeHumidity;
Isn't a Shield just an Mulit of one or more Sensors or Multi's? Can an Mulit have a Mulit as a property?
var weatherShield = new five.Shield({
controller: "PHOTON_WEATHER_SHIELD"
});
weatherShield.on("data", function() {
// hygrometer is an Multi within the weatherShield
// and temperature is a sensor with the hygrometer
hF = this.hygrometer.temperature.fahrenheit;
}
For the record, I am also fine with instantiating the individual sensors and working with them instead of the shield.
var baro = new five.Barometer({
controller: "MPL3115A2",
});
If each of the sensors (Multi) in the shield has its own temperature, why wouldn't you make temperature a property of the Mulit sensor within the shield?
Because the HTU21D and MPL3115A2 are the Multi
components, each contain instances of other classes.
Isn't a Shield just an IMU of one or more Sensors or IMUs?
Sorry, this will sound obnoxious and pedantic, but I don't want you to be misinformed: an "IMU" is an "inertial measurement unit" and refers specifically to multi-sensor modules that serve that purpose. We're only talking about generic multi-sensor modules.
@BrianGenisio I think we can have a Multi
controller that just initializes other Multi
instances.
For the record, I am also fine with instantiating the individual sensors and working with them instead of the shield.
We need a way to make it easy to group these things, it's a challenge, but it's not impossible—we'll figure it out.
@BrianGenisio wdyt?
// This would be a new controller definition inside lib/imu.js
PHOTON_WEATHER_SHIELD: {
initialize: {
value: function(opts) {
var state = priv.get(this);
state.hygrometer = new Multi(
Object.assign({
controller: "HTU21D",
board: this.board,
}, opts)
);
state.barometer = new Multi(
Object.assign({
controller: "MPL3115A2",
board: this.board,
}, opts)
);
}
},
components: {
value: ["barometer", "hygrometer"]
},
barometer: {
get: function() {
return priv.get(this).barometer;
}
},
hygrometer: {
get: function() {
return priv.get(this).hygrometer;
}
}
},
I think it will actually work, even with the component list, because IIRC the Multi instances satisfy the requirements here:
if (this.components && this.components.length > 0) {
this.components.forEach(function(component) {
if (!(this[component] instanceof Emitter)) {
return;
}
this[component].on("change", function() {
this.emit("change", this, component);
}.bind(this));
}, this);
}
Of course it requires Multi
controllers for HTU21D & MPL3115A2, then it's just recursive Multi
controllers. Zany shit!
Yes, @rwaldron. That is mostly what I'm thinking, though I think it can make for a somewhat awkward interface... calling weather.barometer.barometer
.
Here is what i think the consumption of the components should look like:
var hygrometer = new five.Hygrometer( { controller: 'HTU21D' });
hygrometer.on('change', function() {
console.log(this.relativeHumidity);
});
var temperature = new five.Temperature( { controller: 'HTU21D' });
temperature.on('change', function() {
console.log(this.F);
});
var barometer = new five.Barometer( { controller: 'MPL3115A2' });
barometer.on('change', function() {
console.log(this.hPa);
});
var temperature = new five.Temperature( { controller: 'MPL3115A2' });
temperature.on('change', function() {
console.log(this.F);
});
var htu21d = new five.Multi({ controller: 'HTU21D' });
htu21d.hygrometer.on('change', function() {} );
htu21d.temperature.on('change', function() {} );
var mpl3115a2 = new five.Multi({ controller: 'MPL3115A2' });
mpl3115a2.barometer.on('change', function() {} );
mpl3115a2.temperature.on('change', function() {} );
var weather = new five.Multi({ controller: 'PHOTON_WEATHER_SHIELD'});
weather.htu21d.hygrometer.on('change', function() {} );
weather.htu21d.temperature.on('change', function() {} );
weather.mpl3115a2.barometer.on('change', function() {} );
weather.mpl3115a2.temperature.on('change', function() {} );
When you have a shield, ANY of the above interfaces should work for you. When you have a standalone chip, any of them (except for the shield, of course) should work. The only thing I'm not crazy about is calling out the chips by name on the shield. If we call them by component type, then it becomes awkward:
weather.hygrometer.hygrometer.on();
weather.hygrometer.temperature.on();
I can see pros and cons for both ways... perhaps we alias them so they can work either way?
@briangenisio I think that works for me. Another alternative: implement just the chip Multi controllers and then make a plugin module that wrapped them up neatly. We can try both
Ok, good news @dougseven . I worked the HTU21D from scratch, and now I have a fully functioning humidity and temperature sensor working (on my branch). Plus, I've tested it with a stand-alone chip. It works that way too... I might get that one wrapped up as a PR before moving on to the Barometer.
Barometer/Temp (MPL3115A2) is ... tricky. Need to spend some focused time on it. But, progress!
Ok, good news @dougseven . I worked the HTU21D from scratch, and now I have a fully functioning humidity and temperature sensor working (on my branch). Plus, I've tested it with a stand-alone chip. It works that way too... I might get that one wrapped up as a PR before moving on to the Barometer.
That is great news! We can do our workshops and Azure Tour with just the HTU21D - although it would be awesome to get both sensors working. Thanks @BrianGenisio !!!!!
@dougseven Good plan then. I've started a new branch just for the HTU21D PR, and I have an initial PR ready to go: https://github.com/rwaldron/johnny-five/pull/916
It still needs unit tests and a diagram, but it is otherwise ready for you to play with. Let me know how it works for you!
Note that the examples in that PR are for vanilla Arduino. You'll need to modify them to use the particle-io
layer, but that is just at the board creation step. The API to program against the HTU21D doesn't change at all. I've tested this code with the Particle/Weather Shield as well.
@dougseven
You'll need to modify them to use the particle-io layer, but that is just at the board creation step.
Let me make myself useful here. I made this to try out @BrianGenisio's work:
var five = require("johnny-five");
var Photon = require("particle-io");
var board = new five.Board({
io: new Photon({
token: process.env.PARTICLE_TOKEN,
deviceId: process.env.PARTICLE_PHOTON_REDBOARD_1
})
});
board.on("ready", function() {
var multi = new five.Multi({
controller: "HTU21D"
});
multi.on("change", function() {
console.log("Thermometer");
console.log(" celsius : ", this.temperature.celsius);
console.log(" fahrenheit : ", this.temperature.fahrenheit);
console.log(" kelvin : ", this.temperature.kelvin);
console.log("--------------------------------------");
console.log("Hygrometer");
console.log(" relative humidity : ", this.hygrometer.relativeHumidity);
console.log("--------------------------------------");
});
});
@dougseven how much more time is there?
I think I'll have a Barometer POC in a day or so. The AdaFruit library is much easier to implement in J5 than the SparkFun approach. Assuming no snags, pressure, altimeter, and temp will be pretty straight forward. Will not be as bad as I had thought. In general, the AdaFruit examples have been much better for both of these devices. Glad I looked. On Sun, Oct 4, 2015 at 4:10 PM Rick Waldron notifications@github.com wrote:
@dougseven https://github.com/dougseven how much more time is there?
— Reply to this email directly or view it on GitHub https://github.com/rwaldron/johnny-five/issues/912#issuecomment-145383984 .
@dougseven More good news! I have the hard part written for the MPL3115A2: https://github.com/BrianGenisio/johnny-five/tree/mpl3115a2
So far, it is properly exposing pressure and temperature. I'm also successfully harvesting altimeter data... we just don't have a component to expose it yet. That is the next step.
Everything from here is cake. It will still take some time to round it out, but the hard part is done.
@rwaldron Our first Azure Tour stop is in Philadelphia on Oct-13. We will lock down the content for that lab this week. We have a workshop in Amsterdam 2-days later. Then we have a couple weeks before the next one.
@BrianGenisio Thank you!!!
I may not know enough about developing node modules to know how to test this. I cloned your HTU21D branch and I am referencing it locally. I checked the node_modules folder where my test app is and the new hygrometer.js file is there (as a spot check). When I run the code I get the this error:
Dougs-MacBook-Pro:WeatherShield dougseven$ node demo.js
1444030934015 Device(s) particle-io
1444030935198 Connected particle-io
1444030935280 Repl Initialized
>> /Users/dougseven/Development/gh/johnny-five/lib/imu.js:62
io.i2cConfig(opts);
^
TypeError: undefined is not a function
at EventEmitter.Drivers.HTU21D.initialize.value (/Users/dougseven/Development/gh/johnny-five/lib/imu.js:62:12)
at Object.Drivers.get (/Users/dougseven/Development/gh/johnny-five/lib/imu.js:452:12)
at Hygrometer.Controllers.HTU21D.initialize.value (/Users/dougseven/Development/gh/johnny-five/lib/hygrometer.js:12:36)
at new Hygrometer (/Users/dougseven/Development/gh/johnny-five/lib/hygrometer.js:72:10)
at IMU.Controllers.HTU21D.initialize.value (/Users/dougseven/Development/gh/johnny-five/lib/imu.js:560:28)
at new IMU (/Users/dougseven/Development/gh/johnny-five/lib/imu.js:687:10)
at Board.<anonymous> (/Users/dougseven/Development/gh/Demos/photon/WeatherShield/demo.js:12:15)
at Board.emit (events.js:104:17)
at process._tickDomainCallback (node.js:381:11)
My code is the same as @rwaldron code above, but I point to my local johnny-five directory (I also did an npm install
var five = require("../../../johnny-five");
var Photon = require("particle-io");
var board = new five.Board({
io: new Photon({
token: process.env.PARTICLE_KEY,
deviceId: process.env.PARTICLE_DEVICE
})
});
board.on("ready", function() {
var multi = new five.Multi({
controller: "HTU21D"
});
multi.on("change", function() {
console.log("Thermometer");
console.log(" celsius : ", this.temperature.celsius);
console.log(" fahrenheit : ", this.temperature.fahrenheit);
console.log(" kelvin : ", this.temperature.kelvin);
console.log("--------------------------------------");
console.log("Hygrometer");
console.log(" relative humidity : ", this.hygrometer.relativeHumidity);
console.log("--------------------------------------");
});
});
@dougseven What version of particle-io is installed? If you haven't updated since Friday, you probably have an old version that doesn't implement I2C. Please make sure your particle-io version is 0.10.0.
@dougseven Here's a little teaser for you... reading both sensors simultaneously from the particle shield.
Gotta get back to the day job this AM, but I am setting a goal of having both PRs complete by Friday night, but hopefully before that.
What version of particle-io is installed? If you haven't updated since Friday, you probably have an old version that doesn't implement I2C. Please make sure your particle-io version is 0.10.0.
@BrianGenisio that was it. Got it to run, but it didn't seem like the data event handler was firing. I had to go to the office for the day - but I will check it later tonight.
@BrianGenisio @rwaldron - I tested this with the Photon and the SparkFun Weather Shield - works great! Thank you.
@dougseven Both sensors have landed as of 0.8.98. I'd still like to add a Multi
controller for this shield which contains all the sensors. But this is not an Arduino compatible shield, so examples require particle-io and I don't think this project has a precedent for including external IO modules in the examples.
Before I toss it and build it as a separate module, I'm going to test something. Off the side of this board are some pinouts for +/- and SDA/SCL pins. I wonder if we can connect an Arduino to the shield that way, and then we have a case for adding it to J5 directly. I'll give it a shot tonight. But this is all frosting now... the core support for both chips is in J5 proper, and ready to use.
https://github.com/rwaldron/johnny-five/blob/master/docs/hygrometer-htu21d.md https://github.com/rwaldron/johnny-five/blob/master/docs/temperature-htu21d.md https://github.com/rwaldron/johnny-five/blob/master/docs/multi-htu21d.md
https://github.com/rwaldron/johnny-five/blob/master/docs/barometer-mpl3115a2.md https://github.com/rwaldron/johnny-five/blob/master/docs/altimeter-mpl3115a2.md https://github.com/rwaldron/johnny-five/blob/master/docs/temperature-mpl3115a2.md https://github.com/rwaldron/johnny-five/blob/master/docs/multi-mpl3115a2.md
I'd still like to add a Multi controller for this shield which contains all the sensors. But this is not an Arduino compatible shield, so examples require particle-io and I don't think this project has a precedent for including external IO modules in the examples.
@BrianGenisio SparkFun makes a weather shield for Arduino with the same two sensors plus light sensors - https://www.sparkfun.com/products/12081
SparkFun makes a weather shield for Arduino with the same two sensors plus light sensors
I've put together a plugin that wraps all three sensors into a simplified API: https://github.com/rwaldron/j5-sparkfun-weather-shield
celsius
, fahrenheit
& kelvin
properties is an average of both sensor's temperature readings. var Particle = require("particle-io");
var five = require("johnny-five");
var Weather = require("j5-sparkfun-weather-shield")(five);
var board = new five.Board({
io: new Particle({
token: process.env.PARTICLE_TOKEN,
deviceId: process.env.PARTICLE_PHOTON_DEVICE
})
});
board.on("ready", function() {
var weather = new Weather({
variant: "PHOTON",
freq: 200
});
weather.on("data", function() {
console.log("celsius: %d°C", this.celsius);
console.log("fahrenheit: %d°F", this.fahrenheit);
console.log("kelvin: %d°K", this.kelvin);
console.log("pressure: %d kPa", this.pressure);
console.log("feet: %d\"", this.feet);
console.log("meters: %d", this.meters);
console.log("relativeHumidity: %d RH", this.relativeHumidity);
console.log("lightLevel: %d%", this.lightLevel);
console.log("----------------------------------------");
});
});
Love it. I think that means we can close this issue, then? @dougseven has full support now ;)
Awesome :)
Let's hold it open until we resolve the breakout vs shield discrepancy that I mentioned in gitter.
Just tried the plug-in with the photon and the shield. Looks perfect. Nice job.
Seems safe to close this!
This is the device: https://www.sparkfun.com/products/13630
First pass, I plan to support
Anything else that should be supported in the first pass?