I'm not understanding something about the sensor objects and calling class functions by name.
In my setup I have
static st::IS_Button sensor2(F("button1"), PIN_BUTTON_1, 3000, LOW, true, 500);
st::Everything::addSensor(&sensor2);
st::Everything::initDevices();
but when I get to my loop and try the following...
void loop()
{
st::Everything::run();
ledState = digitalRead(PIN_LED);
if (&sensor2->getStatus()) {
digitalWrite(PIN_LED, ledState ? HIGH : LOW);
}
}
....I get 'sensor2' was not declared in this scope. Sorry to be such a novice, but what should I be doing to use the sensor object to call the various class public functions?
The much better place to execute code like you've shown above would be in the "callback()" routine. That routine is called each time the microcontroller sends an update to Hubitat. The name/value text pair is available to parse and then perform whatever other code you'd like.
The specific error your experiencing is due to the fact that the scope of the 'sener2' variable is only valid within the setup() routine. In order to use it within the loop() routine, you'll need to create a global pointer variable outside of both the setup() and loop() routines.
Something like
st::IS_Button* ptrSensor2;
then add to the end of the setup() routine something like
ptrSensor2 = &sensor2;
Then, in the loop() routine use the following syntax
dev:13222022-04-02 10:03:05.155 debugdescription= 'mac:500291FE6C30, ip:c0a85619, port:1f9a, headers:SFRUUC8xLjEgMjAwIE9LDQo=, body:'
dev:13222022-04-02 10:03:05.091 debugUsing ip: 192.168.86.25 and port: 8090 for device: 1322
dev:13222022-04-02 10:03:05.089 debugExecuting 'sendEthernet' refresh
dev:13222022-04-02 10:03:05.088 debugExecuting 'refresh()'
dev:13222022-04-02 10:03:05.086 infoSending REFRESH command to Arduino, which will create any missing child devices.
dev:13222022-04-02 10:03:05.035 infoEnabling Debug Logging for 30 minutes
dev:13222022-04-02 10:03:05.002 infoSetting DNI = C0A85619
dev:13222022-04-02 10:03:05.000 infoArduino IP Address = 192.168.86.25, Hub Port = 8090
dev:13222022-04-02 10:03:04.998 infoHub IP Address = 192.168.86.20, Hub Port = 39501
dev:13222022-04-02 10:03:04.996 infoExecuting 'updated()'
dev:13222022-04-02 10:00:55.044 errorjava.lang.NullPointerException: Cannot execute null+900000 on line 414 (method checkHubDuinoPresence)
which I think is because the Hubduino parent has never received data, so doesn't have a time stamp to work out the presence from.
In my arduino code I am using the identical settings to my other devices, with the exception of the reserved IP for the 8266 (which I've checked is correct).
The arduino serial monitor is behaving a bit oddly (weird non ascii chars):
Enter the following three lines of data into ST App on your phone!
(I have obfuscated the Wifi details - they are correct)
It suggests that it is trying to send data, though should I worry about the line:
Disabling ESP8266 WiFi Access Point
This ESP8266 and the pulse counter worked perfectly on Tasmota - I could see everything over Tasmota's webUI - I just couldn't get the data to appear in HE
One quick follow-up question: I'm more concerned about when Hubitat sends something to the microcontroller, is callback() still the appropriate place to put the code or is their a better place?
Hmm... Stand down on this for a moment...
I had another 8266 lying around, so I gave that a try, and it works.
Slightly worryingly though - I've not updated the IPs in the code yet, so I'm a little surprised it works.....
I'm trying to get the settings right, but I have a rubbish DHCP server (Google Wifi - great consumer device, but terrible for managing IP allocation, looking at devices etc).
There is a much better place for 'sniffing' the incoming data.
In the setup() routine in the sketch, simply make the following change. Or, if you want both a SEND and a RCVD callback, simply create a new callbackRcvd() function and assign that function to the callOnMsgRcvd pointer below.
//Initialize the optional local callback routine (safe to comment out if not desired)
// st::Everything::callOnMsgSend = callback;
st::Everything::callOnMsgRcvd = callback;
So I have no idea what went wrong earlier - I'm blaming the Google Wifi - it's really hard to see what devices have what IPs and what their MACs are.
But I'm up & running with a watts figure, derived from counting the 1 Wh pulses from the meter for one minute & multiplying by 60.
The next desires are:
1/ possibly improve accuracy by timing the interval between a number of pulses and reporting based on that - currently max accuracy is 60W. Though TBH this may not be worth doing.
2/ reporting the actual Energy consumption by passing over the pulse count. This would probably mean storing it in flash so it persisted over power cycles.
3/ expanding to water - I know Hubduino has a water meter set up for analogue, so I ought to be able to use that in conjunction
4/ expanding to GAS - I could just use this, and convert from m3 of gas to kW...
@ogiewon - has anyone done any of these before? I am not a great coder, and whilst I can tell that the architecture of Hubduino is very elegant & flexible, it is (currently at least) a little beyond my understanding. I'm willing & keen to give it a go though!
Have you looked at the ST_Anything PS_PulseCounter device? It is actually designed to handle higher frequency pulses that I am guessing your meter is providing, but it may be useful.
//******************************************************************************************
// File: PS_PulseCounter.h
// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son)
//
// Summary: PS_PulseCounter is a class which implements the SmartThings "Power Meter"-style device capability.
// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the
// the number of counts between polling intervals. At the polling interval, the pulse count is converted
// to engineering units via a linear conversion (engUnits = slope x counts + offset).
//
//
// Create an instance of this class in your sketch's global variable section
// For Example: st::PS_PulseCounter sensor3(F("power1"), 60, 5, PIN_PULSE, FALLING, INPUT_PULLUP, 1.0, 0);
//
// st::PS_PulseCounter() constructor requires the following arguments
// - String &name - REQUIRED - the name of the object - must be in form of "power1", "power2", etc...
// - int interval - REQUIRED - the polling interval in seconds
// - int offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time
// - byte pin - REQUIRED - the GPIO Pin to be used as an digital input (Hardware Interrupt)
// - byte inttype - REQUIRED - which type of Arduino interrupt to trigger the ISR (RISING, FALLING, CHANGE)
// - byte inputmode - REQUIRED - Mode of the digital input Pin (INPUT, INPUT_PULLUP)
// - float cnvslope - REQUIRED - Conversion to Engineering Units Slope
// - float cnvoffset - REQUIRED - Conversion to Engineering Units Offset
I've set one of these up & it's working OK on D7, using a falling edge trigger.
I've tried adding a 2nd on D4 (I'm fairly sure I read somewhere that the ESP8266 only had 2, though a quick google suggests they are on every pin other than 16?) and both readings go awry - they seem to average themselves.
I also saw odd behaviour from the blue LED on the board - with only D7 working it stays on the whole time. When I added D4 it flashed in time with the pulse on D4.
Any suggestions for which pins I should use if I want to use multiple pins?
Might it be interference from one to another? these are only pulsing 80 times a minute or less. I've added some small capacitors in case, and I've enabled INPUT_PULLUP.
I'm wondering about adding some debounce in code in case that helps.
I'd like to run four from one device, but if I have to use an ESP8266 per meter that's OK.
@ogiewon I could do with a quick bit of guidance...
I'm getting on nicely working on modifying PS_PulseCounter to my needs, though it's extending my programming knowledge to cover Classes!
It's given me insight in to the issue I described in the post above.
If I create two instances of PS_PulseCounter:
They look to me to be sharing the interrupt, or possibly the m_nCounts variable, meaning that I don't get a meaningful value out of either.
Is there something special I should be doing - using specific pins, something else?
Or does the ESP8266 only support one interrupt? I'm new to this!
Ideally I'd like to run 4 of these counters from one ESP8266, but if I have to use one for each that's not the end of the world.
Yes, you are correct. The Interrupt Service Routine (ISR) and the m_nCounts variable are being shared amongst all instances of the PS_PulseCounter class. This was done as the ISR could not access the variable otherwise.
You could try to create three more versions of the PS_PulseCounter class, called something like PS_PulseCounter2, PS_PulseCounter3, and PS_PulseCounter4. In each of them, rename both the isrPulse() routine and m_nCounts variable accordingly, and change all references to both within the new .h and .cpp files as well.
It's worth a try, in order to use more than one PS_PulseCounter on a single microcontroller. Just be aware that I am not sure if this will work or not. It may work on some microcontrollers but not on others due to hardware Interrupt limitations.
Please explain exactly how you would envision this working? It might be easy… or it may be challenging. Need some details to understand the requirements and do some analysis.
@ogiewon - that worked a treat! not the nicest code, but I'm fine with it - thanks so much! Have you got patreon or similar so I can send you a beer?
My next step is to add sending of total counts since power on, to allow me to graph hourly, daily, weekly consumption etc.
Would you suggest modding the classes to send two bits of data (I had a look at PS_TemperatureHumidty), or just using the "generic" class, and a global variable for each to transfer the data? I don't think you've sent "Wh" or "kWh" in any of the classes.
I am thinking about Arrival Sensor similar to Samsung Zigbee Arrival Sensor
(already discontinued) but based on Cellphone Bluetooth BLE used as a
Presence Device plus ESP as a Presence Sensor.
When cellphone(s) connects to the ESP8266 (or ESP32) via Bluetooth the HE
gets a Switch On event or whatever what could be used as a Trigger for RM.
Interesting idea... I have never messed around with BLE. I am pretty sure one would need to use an ESP32 as the ESP8266 does not support BLE, IIRC.
Do you have any example Arduino sketches for the ESP32 that demonstrate this functionality? (i.e. the ability to detect a specific device has been connected via BT.)
This is not an Arduino sketch but rather ready to go ESpresence project:
I was/am thinking to try it "as is" but it does not directly integrates with HE.
I don't want to mess up with all other required components in order to get
it working with HE. Unfortunately I am not a SW guru but I am thinking it
could be not a big deal for experts like you to put together all components.
Hubduino already exist. It is very well structured and easy to use.
I guess (amd I hope), ESpresence has a BLE Presence Sensor ready to go.
So maybe it is not a big deal to create a Hubduino BLE Presence Sensor.
I am sure, the HE community will like it a lot.
I will be a first one to try it immediately and help to debug.