@rejoe2 A magnetometer doesn't need a magnet to work, my gas meter doesn't have a magnet and it works fine. Most all smartphones have magnetometers in them to sense direction. However your solution looks to work as well and probably with less code.
dpcr
Posts
-
💬 Water Meter Pulse Sensor -
💬 Water Meter Pulse Sensor@smilvert You could try a magnometer. I successfully used one on my gas meter that didn't have a magnet in it. Look up "gas meter using a magnometer" in this forum. The code is much different than using the standard water meter sketch.
-
💬 Water Meter Pulse Sensor@ladislav Sounds like a radio problem. Are you using a capacitor on the radio power supply pins? A capacitor on all radios in your network. I have a an Ethernet gateway in our basement and a node in our attic that is two floors above it and it works fine using a NRF24 for all radios and the radio power is on the default setting and it communicates fine.
-
💬 Water Meter Pulse SensorHas it ever received a pulse count?
-
Gas Meter Reading Using a Magnetometer@pihome I power mine with an adapter as well. This node sends too much information to be battery powered. I was researching solar because the sensor sits outside on the south side of our home but never followed up on it. Maybe for another day.
-
Gas Meter Reading Using a Magnetometer@Ed1500 Good luck on on your project, keep us updated on your progress. I'm also thinking about trying to measure our electricity consumption using CT's rather than at the meter.
-
Gas Meter Reading Using a Magnetometer@dynamite Makes sense, how would you measures the flow when it gets real low?
-
Gas Meter Reading Using a Magnetometer@Ed1500 As Dynamite said, it measures the change in the magnet field produced by the movement inside of the meter. I believe all ferris metals can have some sort of effect as well as an electrical field (something like that produced by an AA battery) on the sensor. There is no magnet in my gas meter (Rockwell 250). I used an app on my phone to determine the best possible location of the sensor. Look at the first post.
-
Gas Meter Reading Using a Magnetometer@dynamite Just checking in, how is your set up working? We just had some major problems with too many extra pulses. It looks like something you experienced earlier, we added some smoothing to the readMag output similar to what you have in your sketch and it seems to working fine. Any updates?
-
Gas Meter Reading Using a Magnetometer@dynamite I noticed some pulses missing as well. It looks like the newer sketch catches them. I also checked the volume used with our gas suppliers volume used and it was pretty close. We added an error correction variable to try to be more accurate. When I get a chance I'm going to try your sketch, it looks interesting.
-
💬 Domoticz@breimann I didn't do anything special to install Domoticz on a pi3, I just used their instructions for a pi3. Then I used our router to assign the pi a static IP address on our local network. I then set up an OpenVPN connection on our router so I can connect remotely and securely to our home lan (your router needs to have a support VPN). I installed an OpenVPN app on my phone to connect to our local network, then use a browser to go to the IP and port of Domoticz. Hope this makes sense.
-
Gas Meter Reading Using a Magnetometer@dynamite Great idea (top and bottom). We were kicking that around when we made this but wanted to err on the side of missing little to no gas flow. We have a pilot light on our water heater the draws around .1 lpm and I want to capture that as well.
I agree with you on the accuracy of using a magnetometer over a hall or reed switch, but they (hall or reed) are much easy to program. Too bad there isn't a library for converting a sine wave to pulses, don't forget that sometimes it doesn't look like a sine wave.
I'm curious to see how you mounted your magnetometer to your gas meter, mine seems a little too bulky and obtrusive. I did manage to buy another magnetometer and dip it in some stuff called PlastiDip. Its used for insulating the handles of tools. I just haven't switched them out yet to see how well it works.
-
Gas Meter Reading Using a Magnetometer@dynamite I just scanned quickly over your code. So there is no need to store the top and bottom values? What do you do on a power failure? I look forward to hearing from you more.
Do you have any pics of your hardware?
-
Gas Meter Reading Using a Magnetometer@dpcr New Sketch: This one is version 1.0 and works well with the hardware I'm using. It has an interactive start up menu in the serial monitor when starting which allows one to choose several options and var1 (variable used to store the pulse count on the controller) was removed and the pulse count is now stored in FRAM. It's been running for several months with no problem.
/* * Created by Sean Creel <creels15@gmail.com> * * Based on these projects by Henrik Ekblad and Korneliusz Jarzębski: * https://www.mysensors.org/build/pulse_water * https://github.com/jarzebski/Arduino-HMC5883L * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * DESCRIPTION: * Uses an I2C triple-axis magnetometer to measure a home's gas usage by * detecting small fluxuations in the local magnetic field caused by the * meter's bellows pumping in and out. Requires users to determine how * many cycles their meter completes per unit volume of gas flow. */ #define MY_DEBUG //enables debugging of MySensors messages #define MY_RADIO_NRF24 //lets MySensors know what radio you're using #include <MySensors.h> #include <Wire.h> //I2C communications library #include <Adafruit_FRAM_I2C.h> //Adafruit FRAM memory library #define CHILD_ID 1 //ID of the sensor child #define SLEEP_MODE false //prevent sensor from sleeping #define address 0x1E //0011110b, I2C 7bit address of HMC5883 magnetometer #define topAddr 4 //address of Top in FRAM #define bottomAddr 6 //address of Bottom in FRAM #define pulseAddr 0 //address of pulseCount in FRAM //USER-DEFINED CONSTANTS #define METRIC true //specifies the units of measurement #define AXIS "Y" //specifies which axes of the magnetometer to read from (multiple axes permitted, e.g. "ZX" or "YXZ") #define CYCLES_PER_CUFT 8 //cycles of the meter's bellows per cubic foot of gas (varies by meter model) #define NUM_DIVISIONS 10 //desired number of subdivisions per cycle. higher => more accuracy, lower => more tolerant of noise #define ERR 0.00221513400975639000 //used to fix discrepancies between theoretical and actual volume per pulse (vpp) #define LEN 3 //number of flow rate measurements to save for moving average. set to 1 if you want to send raw flow data instead #define SEND_FREQUENCY 30000 //Minimum time between messages to the GW (msec) #define TOL 50 //margin of error to account for noise coming from the sensor bool autoDetect = false; //true if the program is auto detecting Top and Bottom bool rising = true; //whether or not a pulse has been triggered bool safe = false; //whether or not it is safe to switch directions unsigned long pulseCount = 0; //total number of pulses measured ever unsigned long oldPulseCount = 0; //old total double vpp = ERR + (METRIC ? 28.3168 : 1.0) / (CYCLES_PER_CUFT * 2 * (NUM_DIVISIONS + 1));//Volume of gas per pulse ft^3/L unsigned long lastSend = 0; //time since last transmission - msec double flow [LEN]; //array of previous gas flow rate measurements double avgFlow = 0; //average of all elements in flow array double oldAvgFlow = 0; //previous average flow int b = 0; //magnetic field reading int oldB = 0; //previous magnetic field reading int top = 0; //highest magnetic field registered from meter (Ga)Initialize low if using autoDetectMaxMin int bottom = 0; //lowest magnetic field registered from meter (Ga) Initialize high if using autoDetectMaxMin int newTop = -9000; //potential new Top int newBottom = 9000; //potential new Bottom int increment = 0; //space b/w dividers int counter = 0; //used to count pulses over periods longer than SEND_FREQUENCY MyMessage flowMsg(CHILD_ID,V_FLOW); MyMessage volumeMsg(CHILD_ID,V_VOLUME); Adafruit_FRAM_I2C fram = Adafruit_FRAM_I2C(); void setup(){ //Initialize Serial, I2C, and FRAM communications Serial.begin(9600); Wire.begin(); fram.begin(); //Put the HMC5883 IC into the correct operating mode Wire.beginTransmission(address); //open communication with HMC5883 Wire.write(0x02); //select mode register Wire.write(0x00); //continuous measurement mode Wire.endTransmission(); //Prompt user for permission to clear all or part of FRAM Serial.println("Do you wish to clear all or part of long-term memory?"); Serial.println("Please enter a number 0-3:"); Serial.println("0: (default) Clear nothing"); Serial.println("1: Clear Top and Bottom"); Serial.println("2: Clear Pulse Count"); Serial.println("3: Clear Top, Bottom, and Pulse Count"); int choice = 0; lastSend = millis(); while(Serial.available() == 0 && millis() - lastSend < 30000); //wait 30s max for user input choice += Serial.parseInt(); if(choice == 1){ clearFram(4,8); Serial.println("Top and Bottom values reset"); } else if(choice == 2){ clearFram(0,4); Serial.println("Pulse Count reset"); } else if(choice == 3){ clearFram(0,8); Serial.println("All stored values reset"); } //get pulseCount from FRAM pulseCount = readUL(pulseAddr); oldPulseCount = pulseCount; //get Top and Bottom from FRAM newTop = readInt(topAddr); newBottom = readInt(bottomAddr); updateBounds(); //WARNING: MAKE SURE GAS IS RUNNING ON FIRST RUNNING OF THIS PROGRAM!!! if(top == 0 && bottom == 0){ autoDetect = true; newTop = -9000; newBottom = 9000; //determine max and min magnetic field strength over a few minutes Serial.println("FRAM has been cleared. Auto-detecting max and min magnetic field reading."); Serial.println("WARNING: MAKE SURE GAS IS RUNNING!!"); lastSend = millis(); while(millis() - lastSend < 120000){ readMag(); detectMaxMin(); //display details Serial.print("Magnetic Field: "); Serial.print(b); Serial.print(" Top: "); Serial.print(newTop); Serial.print(" Bottom: "); Serial.print(newBottom); unsigned long remainingTime = 120000 + lastSend - millis(); Serial.print(" Time remaining: "); Serial.print(remainingTime / 60000); Serial.print(":"); remainingTime = (remainingTime % 60000) / 1000; if(remainingTime >= 10){ Serial.println(remainingTime); } else{ Serial.print("0"); Serial.println(remainingTime); } } updateBounds(); autoDetect = false; } readMag(); oldB = b; while(abs(b - oldB) < increment / 2){ //wait until difference b/w b and oldB is greater than half an increment readMag(); } rising = (b > oldB); Serial.println(rising ? "Magnetic field is rising" : "Magnetic field is falling"); Serial.print("Volume Per Pulse = "); Serial.print(vpp,16); Serial.println(METRIC ? " L/pulse" : "cuft/pulse"); lastSend = millis(); } void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo("Gas Meter", "1.0 (4/4/17)"); // Register this device as Gas sensor present(CHILD_ID, S_GAS); } void loop(){ //detecting magnetic pulses - variable boundary method while(millis() - lastSend < SEND_FREQUENCY){ //check if the signal has significantly increased/decreased if(abs(oldB - b) > increment){ pulseCount ++; //increment or decrement oldB by one increment based on direction oldB += rising ? increment : -1 * increment; safe = false; //reset safe now that oldB has updated } //check if the signal has recently switched directions else if(safe){ //first make sure b has moved a significant distance from oldB if((rising && b <= oldB) || (!rising && b >= oldB)){ pulseCount ++; //add one extra pulse rising = !rising; //update direction safe = false; } } //take another reading readMag(); //check if b has moved a significant distance from oldB if(abs(b - oldB) > TOL / 2){ safe = true; } //update newTop and newBottom detectMaxMin(); } //shift all flow array elements to the right by 1, ignore last element for(int idx = LEN - 1; idx > 0; idx--){ flow[idx] = flow[idx - 1]; } //calculate newest flow reading and store it as first element in flow array flow[0] = (double)(pulseCount - oldPulseCount) * vpp * 60000.0 / (double)SEND_FREQUENCY; //display flow array state Serial.print("Flow Array State: ["); for(int idx = 0; idx < LEN - 1; idx++){ Serial.print(flow[idx]); Serial.print("|"); } Serial.print(flow[LEN - 1]); Serial.println("]"); //calculate average flow avgFlow = 0; //reset avgFlow for(int idx = 0; idx < LEN; idx++){ //calculate weighted sum of all elements in flow array avgFlow += (flow[idx] * (LEN - idx)); } avgFlow /= (LEN * (LEN + 1) / 2); //divide by triangle number of elements to get linear weighted average Serial.print("Average flow: "); //display average flow Serial.println(avgFlow); //send flow message if avgFlow has changed if(avgFlow != oldAvgFlow){ oldAvgFlow = avgFlow; send(flowMsg.set(avgFlow, 2)); } //send updated volume data if necessary if(pulseCount != oldPulseCount){ //send volume data to gw send(volumeMsg.set(((double)pulseCount * vpp / (METRIC ? 1000.0 : 1)), 3)); //store updated pulse count total in FRAM writeUL(pulseAddr,pulseCount); counter += (pulseCount - oldPulseCount); //update counter if(counter >= ((NUM_DIVISIONS + 1) * 2)){ updateBounds(); //update bounds if at least 1 cycle has been read counter = 0; //reset counter } oldPulseCount = pulseCount; //update old pulse count total } lastSend = millis(); } void updateBounds(){ if((top != newTop) && (bottom != newBottom)){ //check if anything has actually changed //lock in Top and Bottom top = newTop; bottom = newBottom; //recalculate increment to match new top and bottom increment = (top - bottom - (2 * TOL)) / NUM_DIVISIONS; //store updated Top and Bottom in FRAM writeInt(topAddr,top); writeInt(bottomAddr,bottom); //reset newTop and newBottom newTop = -9000; newBottom = 9000; //display new bounds Serial.println("NEW BOUNDARIES SET:"); Serial.print("Top = "); Serial.println(top); Serial.print("Bottom = "); Serial.println(bottom); Serial.print("Increment = "); Serial.println(increment); } } void detectMaxMin(){ if(b > newTop){ newTop = b; //update newTop if new max has been detected } else if(b < newBottom){ newBottom = b; //update newBottom if new min has been detected } } void writeInt(int addr, int val){ //write an int value to FRAM byte b = highByte(val); fram.write8(addr,b); b = lowByte(val); fram.write8(addr + 1,b); } void writeUL(int addr, unsigned long val){ //write an unsigned long falue to FRAM byte b = B00000000; for(int idx = 0; idx < sizeof(unsigned long); idx++){ b = val >> 8 * (sizeof(unsigned long) - 1 - idx); fram.write8(addr + idx,b); } } unsigned long readUL(int addr){ //read an unsigned long value from FRAM unsigned long result = 0; for(int idx = 0; idx < sizeof(unsigned long); idx++){ result = result << 8; result += (unsigned long)fram.read8(addr + idx); } return result; } int readInt(int addr){ //read an int value from FRAM int result = 0; result += (int)fram.read8(addr); result = result << 8; result += (int)fram.read8(addr + 1); return result; } void clearFram(int first, int last){ for(int addr = first; addr < last; addr++){ fram.write8(addr,byte(0)); } } void readMag(){ static int x = 0, y = 0, z = 0; //Tell the HMC5883 where to begin reading data Wire.beginTransmission(address); Wire.write(0x03); //select register 3, X MSB register - was called Wire.send but the compiler had an error and said to rename to to Wire.write Wire.endTransmission(); //Read data from each axis, 2 registers per axis Wire.requestFrom(address, 6); if(6<=Wire.available()){ x = Wire.read()<<8; //X msb x |= Wire.read(); //X lsb z = Wire.read()<<8; //Z msb z |= Wire.read(); //Z lsb y = Wire.read()<<8; //Y msb y |= Wire.read(); //Y lsb } if(String(AXIS).equalsIgnoreCase("X")){ b = x; } else if(String(AXIS).equalsIgnoreCase("Y")){ b = y; } else if(String(AXIS).equalsIgnoreCase("Z")){ b = z; } else if(String(AXIS).equalsIgnoreCase("XY") || String(AXIS).equalsIgnoreCase("YX")){ b = x * x + y * y; } else if(String(AXIS).equalsIgnoreCase("XZ") || String(AXIS).equalsIgnoreCase("ZX")){ b = x * x + z * z; } else if(String(AXIS).equalsIgnoreCase("YZ") || String(AXIS).equalsIgnoreCase("ZY")){ b = y * y + z * z; } else if(String(AXIS).equalsIgnoreCase("XYZ") || String(AXIS).equalsIgnoreCase("XZY") || String(AXIS).equalsIgnoreCase("YXZ") || String(AXIS).equalsIgnoreCase("YZX") || String(AXIS).equalsIgnoreCase("ZYX") || String(AXIS).equalsIgnoreCase("ZXY")){ b = x * x + y * y + z * z; } else { b = 0; } if(!autoDetect){ //show real-time magnetic field, pulse count, and pulse count total Serial.print("Magnetic Field: "); Serial.print(b); Serial.print(rising ? " Rising, " : " Falling, "); Serial.print("next pulse at: "); Serial.print(rising ? oldB + increment : oldB - increment); Serial.print(" Current Number of Pulses: "); Serial.print(pulseCount - oldPulseCount); Serial.print(" Last Total Pulse Count Sent to GW: "); Serial.println(oldPulseCount); } }``` -
Can a Node Send json?@AWI Thanks for all your information, it gives me some direction. So from what I have read it sounds like MySensors can't send a json command to Domoticz.
-
Can a Node Send json?@gohan No I haven't, I'll give it a try. Thanks.
-
Can a Node Send json?Please forgive my ignorance but I have searched and searched and not found what I was looking for. Please help.
I am making an RFID garage door opener (another) using the MIFARE Classic tags and a MySensors Node. It differs in that I am using the tags to store the tag holder name and encryption keys A & B (I know the generic MIFARE classic encryption has been hacked). What I am trying to do is send the card holders name, time scanned, time access granted or denied to Domoticz. I initially tried a text sensor (V_TEXT) but it only held 16 characters. However using json I can enter up to 40 easily. I can't use the Domoticz logs because from what I have found they only hold their log for several days at the max. I would rather have a dedicated log just for the garage door RFID system.
My question is, is there a way to send a json command through the mysensors network to my Ethernet gateway then onto Domoticz which is on a Pi on the same network.
Here is a the json format that Domoticz accepts:
http://"Domoticz_IP":8080/json.htm?type=command¶m=udevice&idx="IDX_of_TextSensor"&nvalue=0&svalue=Hello World -
RFID Log@martins It worked out well, I had to tweak it a bit for my situation, but all is well. Thanks for pointing me in the right direction.
-
RFID Log@martins Thanks so much, I'll give it a try and let you know how it works out. In my node I'm saving (FRAM) the UID along with the name of the person who hold the tag, so I'd like to send not only the UID but the persons name as well. Again thanks so much for pointing me in the right direction.
-
RFID LogI am developing an RFID read/writer based on the one in the hardware section here that actuates our garage door. I have a functioning Ethernet gateway, several function nodes and am using Domoticz as a controller. What I would like to do is write to the Domoticz log when a card is scanned. I would like to keep a record of who comes and goes. I can't seem to find any documentation on how to do this. Any suggestions?
I have thought about using a pi and write to the Domoticz log through json but I would rather use the MySensors network.