Closed antonskv closed 6 years ago
OK, i was able to directly interact with device though NodeJS USB module. But i'd like to thank you for providing the groundwork for it.
I would've never been able to decode the stream of crap coming out of it, without having your code as a reference.
These bits sent to the usb interface gave me what i need: [0x7b, 0x03, 0x40, 0x7d]
Response raw returns: 123, 0, 34, 97, 0, 248, 24, 0, 204, 31, 127, 255, 255, 127, 255, 255, 127, 255, 255, 127, 255, 255, 127, 255, 255, 64, 125, 0, 64, 125, 44, 0, 100, 64, 125, 0, 17, 52, 2, 19, 91, 111, 50, 180, 118, 22, 252, 75, 130, 231, 38, 145, 108, 52, 62, 225, 213, 101, 135, 36, 224, 37, 85, 166
Sensor 1 Bit 2: Temp 1 Bit 3: Humidity 1
Sensor 2 Bit 5: Temp 2 Bit 6: Humidity 2
Sensor 3 Bit 8: Temp 3 Bit 9: Humidity 3
Temperatures divided by 10, gives actual celcius value of the temperature on the sensor.
Cheers!
This is really awesome Anonskv.
Would you mind sharing your NodeJS script?
OK, i was able to directly interact with device though NodeJS USB module. But i'd like to thank you for providing the groundwork for it.
I would've never been able to decode the stream of crap coming out of it, without having your code as a reference.
These bits sent to the usb interface gave me what i need: [0x7b, 0x03, 0x40, 0x7d]
Response raw returns: 123, 0, 34, 97, 0, 248, 24, 0, 204, 31, 127, 255, 255, 127, 255, 255, 127, 255, 255, 127, 255, 255, 127, 255, 255, 64, 125, 0, 64, 125, 44, 0, 100, 64, 125, 0, 17, 52, 2, 19, 91, 111, 50, 180, 118, 22, 252, 75, 130, 231, 38, 145, 108, 52, 62, 225, 213, 101, 135, 36, 224, 37, 85, 166
Sensor 1 Bit 2: Temp 1 Bit 3: Humidity 1
Sensor 2 Bit 5: Temp 2 Bit 6: Humidity 2
Sensor 3 Bit 8: Temp 3 Bit 9: Humidity 3
Temperatures divided by 10, gives actual celcius value of the temperature on the sensor.
Cheers!
I also thank the author of this driver for all his efforts. But for me, this whole Weewx & Weewx-hp3000 experience has been very tough. All I want is to feed a home automation system with temperatures. I think your nodejs script will work!
Just to contribute something towards the discussion; I was able to get the data out with this test script. I guess I will have to modify it slightly to make it compatible with for instance Telegraf (for Influxdb).
#!/usr/bin/env python2
import sys, traceback
import usb.core, usb.util
from time import sleep
def trimbuffer(buf):
i = 0
while i < len(buf):
if (i > 0 and buf[i] == 0x7d and buf[i-1] == 0x40):
break
i += 1
return buf[0:i+1]
def ws3000_write(command):
print "ws3000_write: entry"
VENDOR = 0x0483
PRODUCT = 0x5750
CONFIGURATION = 0
try:
print "Detecting device..."
device = usb.core.find(idVendor=VENDOR, idProduct=PRODUCT)
if device is None:
print("Is the WS-3000 connected?")
sys.exit(1)
print("Device found")
# Device busy if managed by the kernel
if device.is_kernel_driver_active(CONFIGURATION):
print("Detaching kernel driver")
device.detach_kernel_driver(CONFIGURATION)
# WS-3000 has only one configuration
device.set_configuration()
# control
print "Sending control packet"
#device.ctrl_transfer(0x21, 10, 0, 0, None)
device.ctrl_transfer(0, 9, 1, 0, None)
commands = [0x41, 0x06, 0x08, 0x09, 0x05, 0x03, 0x04]
#commands = [0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03]
for command in commands:
request = [0x7b, command, 0x40, 0x7d]
padding = [0x0] * 60
request.extend(padding)
print "Sending command: ", request
device.write(0x01, request, 100)
data = device.read(0x82, 64, 100)
data = trimbuffer(data)
print data
print len(data)
#for value in data:
# print hex(value)
sleep(10)
except:
print "An error occurred:", sys.exc_info()
traceback.print_exc(file=sys.stdout)
usb.util.dispose_resources(device)
print("Starting tests...")
ws3000_write("")
print("Tests completed")
Source: https://www.mail-archive.com/weewx-user@googlegroups.com/msg09026.html
(Apologies for delay in response, it was holidays and all that)
Oh man, i forgot about this thing, it's been so long.... haha. I picked Node (and this was my first attempt at coding in NodeJS) because it's asynchronous, and multiple things can be going on at same time.
Here is how I did it. Please mind i'm not a NodeJS programmer, so it's probably done in sub-optimal way, and feel free to improve. I did this because back in the day i was running a small air cooled datacenter. So i needed 3 temperatures, outside, interior cold side, and interior hot side (where exhaust was going out). In hindsight i probably could've configured bunch of Arduinos with sensors to do the same thing, but this station was already there, so i decided to take a crack at it, and with some annoyance i got it done.
You need to pull USB module into your Node libraries, install instructions are here: https://www.npmjs.com/package/usb
And here is my amateur-style NodeJS module, it's part of bigger app, but this should be enough as a sample. It just opens a USB device and then starts sending bits to WS3000 at whatever interval you specify in the constructor. Then endpoint on('data', ... function reads and parses the response from WS3000.
/* FILENAME: AmbientWeather3000.js */
const usb = require('usb');
module.exports = class AmbientWeather3000
{
constructor(interval){
/* @NOTE: This is AmbientWeather 3000 vendor/device ID */
// VendorID: 0x0483 (1155)
// ProductID: 0x5750 (22352)
this._usbVendorId = 1155;
this._usbProductId = 22352;
this._interval = interval;
this._intervalVariable = null;
this._device = null;
this._deviceOpen = false;
this._outside = {
temp: 0,
humidity: 0
};
this._coldside = {
temp: 0,
humidity: 0
};
this._hotside = {
temp: 0,
humidity: 0
};
this.startScraping();
};
set device(device){ this._device = device; };
get device() { return this._device; };
set deviceOpen(isOpen){ this._deviceOpen = isOpen; };
get deviceOpen() { return this._deviceOpen; };
set outside(outside) { this._outside = outside; };
get outside() { return this._outside; };
set coldside(coldside) {this._coldside = coldside; };
get coldside() { return this._coldside; }
set hotside(hotside) { this._hotside = hotside; };
get hotside() { return this._hotside; }
get interval() { return this._interval; };
set intervalVariable(intervalVariable){ this._intervalVariable = intervalVariable; };
get intervalVariable(){ return this._intervalVariable; };
startScraping(){
console.log('['+new Date()+'] Starting scraping AmbientWeather 3000 at ' + (this.interval / 1000).toFixed(2) + ' seconds..' );
var _this = this;
try
{
this.device = usb.findByIds(1155, 22352);
if(this.device)
this.device.open();
else
throw Error("Cannot open WS-3000 USB device");
if (this.device.interface(0).isKernelDriverActive()) {
this.device.interface(0).detachKernelDriver();
}
this.deviceOpen = true;
this.device.interface(0).claim();
}
catch(e)
{
console.log("ERROR: Cannot open USB device for streaming: " + e);
process.exit();
}
this.device.interface(0).endpoint(130).startPoll(3, 64);
this.device.interface(0).endpoint(130).on('data', function(data){
var fullArray = [];
for(var i=0 ; i < data.length ; i++)
{
fullArray.push(data[i]);
}
//console.log( "RAW: (Bit Length: "+fullArray.length+")" + fullArray.join(', ') );
var msb1 = fullArray[1];
var temp1 = (msb1 * 256 + fullArray[2]) / 10.0;
var hum1 = fullArray[3];
var msb2 = fullArray[4];
var temp2 = (msb2 * 256 + fullArray[5]) / 10.0;
var hum2 = fullArray[6];
var msb3 = fullArray[7];
var temp3 = (msb3 * 256 + fullArray[8]) / 10.0;
var hum3 = fullArray[9];
console.log( "[" + new Date() + "] Outside: " + temp1 + "°C " + hum1 + "% " + " | Cold-side: " + temp3 + "°C " + hum3 + "% " + " | Hot-side: " + temp2 + "°C " + hum2 + "%" );
_this.outside = { temp: parseFloat(temp1), humidity: hum1 };
_this.coldside = { temp: parseFloat(temp3), humidity: hum3 };
_this.hotside = { temp: parseFloat(temp2), humidity: hum2 };
//console.log( util.inspect(currentData) );
}).on('error', function(error){
console.log( "ERROR: Problem receiving data from USB: " + error );
});
var _this = this;
_this.device.interface(0).endpoint(1).transfer([0x7b, 0x03, 0x40, 0x7d], function(error){
if(error)
console.log("Error sending command to WS-3000: " + error);
});
this.intervalVariable = setInterval(function(){
_this.device.interface(0).endpoint(1).transfer([0x7b, 0x03, 0x40, 0x7d], function(error){
if(error)
console.log("Error sending command to WS-3000: " + error);
});
}, this.interval);
};
};
Then whichever main script you are using it in you would do something like:
/* Include the module at the top */
const AmbientWeather3000 = require('./AmbientWeather3000');
/* Then create this object with 60000 interval or whatever interval you want */
var aw3000 = new AmbientWeather3000( 60000 );
/* Then temperatures will be available like this, you probably would put it into a loop */
console.log( 'Temp: ' + aw3000.outside.temp );
console.log( 'Humidity: ' + aw3000.outside.humidity );
Hope this is enough to get you started!
Hi Matt,
It took some time to get somewhere. I followed instructions from other two tickets, cloned weewx usb branch, ran ./setup.py install. My weewx is located in /home/weewx
Then i followed instructions as per the README. It was still giving weeusb not found. I figured it was something about paths that was missing. I added lines into your driver in the beginning:
I suppose this should work as well, for some reason it doesn't:
export PYTHONPATH=$PYTHONPATH:/home/weewx/bin:/home/weewx
I haven't coded Python before, so maybe i'm doing something wrong. I have WS-3000-X3 connected through USB datacable to Raspberry Pi. This is the output from syslog when i plug it in:
Feb 3 19:57:49 localhost kernel: [202842.134086] usb 1-1.4: USB disconnect, device number 5 Feb 3 19:57:53 localhost kernel: [202846.264314] usb 1-1.4: new full-speed USB device number 7 using dwc_otg Feb 3 19:57:53 localhost kernel: [202846.397659] usb 1-1.4: New USB device found, idVendor=0483, idProduct=5750 Feb 3 19:57:53 localhost kernel: [202846.397668] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3 Feb 3 19:57:53 localhost kernel: [202846.397672] usb 1-1.4: Product: By viewtool Feb 3 19:57:53 localhost kernel: [202846.397676] usb 1-1.4: Manufacturer: MyUSB_HID Feb 3 19:57:53 localhost kernel: [202846.397680] usb 1-1.4: SerialNumber: 8C6487D20934 Feb 3 19:57:53 localhost kernel: [202846.400775] hid-generic 0003:0483:5750.0006: hiddev0,hidraw0: USB HID v1.10 Device [MyUSB_HID By viewtool] on usb-3f980000.usb-1.4/input0 Feb 3 19:57:54 localhost mtp-probe: checking bus 1, device 7: "/sys/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4" Feb 3 19:57:54 localhost mtp-probe: bus: 1, device: 7 was not an MTP device
When i try to run wee_device, script just dies, i looked at the source, i can't understand why there is no output saying something more than just crickets. I did run wee_config --reconfigure with your driver specified.
When i try to run your script directly it gives me a "pipe error":
I see that my EP IN and OUT for this device is 0x82 and 0x01 instead of 0x82 and 0x02 that your driver defines inside the script. So i tried adjusting it to 0x01 value, but still got "Pipe Error".
My device shows up as /dev/usb/hiddev1 and here is output from lsusb -v:
I run a small boutique Data Center, and i need to get 3 temperature/humidity readings. Outside, inside cold side, and inside hot side. I don't need historical data, just the live numbers. I have those 3 wireless sensors in place, and central piece is reading them fine.
My app that reads data from equipment is written in NodeJS. I was going to just use weewx to write current data to a JSON file at like 30 second interval, and NodeJS app to read the file and take stats along with other data and push to ElasticSearch.
Since you decoded the protocol this device uses, perhaps you would know if there is a way to just read the data directly from the device using something like https://github.com/tessel/node-usb?
I mean that library should allow claiming a USB device and sending commands to specific hw address and receiving temperature data back from it. But even just making it work through weewx would be already a huge help.
Thanks for making this driver btw, i've been breaking my head for days how to get this done, i'm as far along as ordering Rasperry Zero with sensor boards to make custom temperature/humidity devices. But that might be unnecessary work, if only i could get this thing working =))
Cheers.