ToniA / arduino-heatpumpir

An Arduino library to control split-unit heatpumps over Infrared
GNU General Public License v2.0
389 stars 141 forks source link

Frequency accuracy #32

Open waj opened 7 years ago

waj commented 7 years ago

I was looking for a library to control my AC from an ESP8266 and this one worked on the first try. Thank you for this! (I have a Carrier compatible AC)

However, I noticed that with this library I have to point my IR led directly to the AC, otherwise the signal was ignored. I would have assumed I didn't have enough power in my circuit but I noticed something strange: while trying another library (https://github.com/markszabo/IRremoteESP8266) and sending raw codes, even though I couldn't get my AC to work properly, the AC was beeping even with my IR led pointing somewhere else.

So I did a little research and it seems that library makes a better effort with the accuracy of the signal frequency. The authors improved that some time ago to take into account rounding and the time the instructions affects the carrier periods: https://github.com/markszabo/IRremoteESP8266/commit/178b09d5eb0448c73fb839090500ccff6aedd4ab

I tested then your library but using a new implementation of the IRSender that forwards the calls to mark and space to the IRremoteESP8266 implementation:

class IRsendSender : public IRSender {
public:
  IRsendSender(uint8_t pin);
  void setFrequency(int frequency);
  void space(int spaceLength);
  void mark(int markLength);

private:
  IRsend ir;
};

IRsendSender::IRsendSender(uint8_t pin) : IRSender(pin), ir(pin) {
  ir.begin();
}

void IRsendSender::setFrequency(int frequency) {
  ir.enableIROut(frequency);
}

void IRsendSender::space(int spaceLength) {
  ir.space(spaceLength);
}

void IRsendSender::mark(int markLength) {
  ir.mark(markLength);
}

And the result was amazing :-). I was able to control my AC without having to point my IR led directly.

So, I wonder what's the best approach to improve this in your library as well. Should be shamelessly copy the implementation from IRremoteESP8266?. Should we include the wrapper I just created in your library instead?

ToniA commented 7 years ago

Thanks, this sounds really promising :) I've been struggling with the poor range, and haven't really had an idea why it was so poor. Seems like integrating with IRremoteESP8266 would not be that hard, but this of course brings in a dependency into another library.

moskovskiy82 commented 7 years ago

Is it only working on esp8266? Or arduino will also be affected?

ToniA commented 7 years ago

I think the accuracy was poor only on ESP8266. On Arduino you are much closer to the 'bare metal'

Muhamed-Reyad commented 6 years ago

Hi im a total noby and i tried replacing the default implementation with the one from IRremoteESP8266 but i kept having all kinds of compilation errors.

Can any of you guys please attach their edited versions of the IRSender.h and IRSender.cpp ( im assuming those are the ones in question) any help would be much appreciated thnx

arion-p commented 6 years ago

Hi, What is the status of this issue? I see that there was some implementation in dev branch but it was never merged to master. Is the dev branch working? will this be abandoned or will it eventually make it to master?

My Mitsubishi FD seems to be very sensitive to the exact frequency of the signal (apparently uses a very steep band pass filter to eliminate interference), so I would like to try this fix.

ToniA commented 6 years ago

I merged in the IRRemoteESP8266 change from the 'dev' branch, let me know if it works better.

arion-p commented 6 years ago

Thank you for your immediate response.

Unfortunately I cannot test in my current project (ESPEasy + P115) as the current version of IRRemoteESP8266 (v2.42) is incompatible with the one used in ESPEasy (patched 1.2.0).

I will have to create a test project and try that, but it will take me some time.

ToniA commented 6 years ago

Today I took the latest ESPEasy from the 'mega' branch, added src/_P115_HeatpumpIR.ino from the ESPEasy playground, added the latest HeatpumpIR into lib/HeatpumpIR and tried to compile (it didn't). The version of IRRemoteESP8266 is really old, so I needed to apply this change to HeatpumpIR library:

diff --git a/IRSender.h b/IRSender.h
index a6bb13c..756d654 100644
--- a/IRSender.h
+++ b/IRSender.h
@@ -7,7 +7,7 @@
 #include <Arduino.h>

 #ifdef ESP8266
-#include <IRsend.h>  // From IRremoteESP8266 library
+#include <IRremoteESP8266.h>  // From IRremoteESP8266 library
 #endif

 class IRSender

After this change the ESPEasy compiles, but it still uses the 'bitbang' method for PWM. If you change line 94 on the plugin code to this:

Plugin_115_irSender = new IRSenderIRremoteESP8266(irPin);

... it should use the IRremoteESP8266 PWM implementation. I didn't try with a real heatpump device, but at least my red led is blinking, so there's a very good chance this might work.

arion-p commented 6 years ago

I will be away for a couple of weeks, so I cannot test. But I will when I get back. IIRC the version in ESPEasy does not include the timing enhancements discussed here (it is a patched v1.2.0), but I will test nonetheless.

In the mean time I took a different route. I "copied" the logic from IRremoteESP8266 simplifying the code where necessary (e.g. duty cycle is always 50%). There was only a slight improvement in range. The calibrated period was 22 uS (instead of 26 uS) but that didn't make much difference. So I'm starting to think my issue might not be related.

I will post the code in case you want to include it.

ToniA commented 6 years ago

Latest ESPEasy Mega also works with latest IRremoteESP8266 + P115 if you delete plugin files _P015_IR.ino and _P035_IRTX.ino. So this way you can use the latest IRremoteESP8266 'as is'.

N-Storm commented 5 years ago

IRSenderESP8266 indeed are much more accurate than IRSenderBitBang. I've measured actual period delays with working WiFi and at 38 kHz carrier it's ~30 us with BitBang method: изображение

I've tried to improve it by replacing delayMicroseconds with ESP.getCycleCount routines which should account sub-us periods. Ended up with 29 us periods for now. Probably should take other delays into account or use an NMI (best way probably on ESP8266).

PS: IRremoteESP8266 routines show 26.5 us periods for me which is the closest one to 38 kHz (it's ~37.74 kHz) carrier.

EDIT: I've managed to compensate that by subtracting experimentally found number of cycles and was able to get a good almost exact 38 kHz carrier out of ESP8266 with getCycleCount. But later I've found that built-in ESP8266 SDK function startWaveform() which uses Timer1 and us half-period times gives almost exact and stable carrier frequency: изображение

I'll create a pull request for my new BitBang class which uses this function once I test it deeply.

N-Storm commented 5 years ago

Added 2 new more accurate classes on my fork here https://github.com/N-Storm/arduino-heatpumpir/pull/3 Waiting on @ToniA to merge current pull requests from my fork to submit new.

N-Storm commented 5 years ago

Fixed in https://github.com/ToniA/arduino-heatpumpir/pull/73