Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IRremoteESP8266 in a python library #2067

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/UnitTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ jobs:
run: (cd tools; make all)
- name: Run tools unit tests
run: (cd tools; make run_tests)
- name: Build swig extension and run simple test
run: (cd python; make testdocker)

Unit_Tests:
runs-on: ubuntu-latest
Expand Down
124 changes: 124 additions & 0 deletions python/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make run_tests - makes everything and runs all test
# make run-% - run specific test file (exclude .py)
# replace % with given test file
# make clean - removes all files generated by make.

# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.

ifeq (,$(wildcard ./.dockerenv))
SWIGTYPE = local
else
SWIGTYPE = global
endif

# Where to find user code.
SRC_DIR = ../src

# Where to find test code.
TEST_DIR = ../test

INCLUDES = -I$(SRC_DIR) -I$(TEST_DIR)
DEFFLAGS = -DUNIT_TEST -DSWIGLIB
# Flags passed to the preprocessor.
# Set Google Test's header directory as a system directory, such that
# the compiler doesn't generate warnings in Google Test headers.
CPPFLAGS += -D_IR_LOCALE_=en-AU -fPIC $(DEFFLAGS)

# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11

PYTHONINCL = $(shell python3-config --includes)

objects = $(patsubst %.cpp,%,$(wildcard *.cpp))

all : _irhvac.so

library : $(objects)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,lib_irhvac.so -o _irhvac.so $(COMMON_OBJ)

swig : libirhvac_wrap.cxx
ifneq (,$(wildcard /.dockerenv))
SWIG_LIB=$(shell realpath -qe swig-4.2.0/Lib) ./swig-4.2.0/swig $(INCLUDES) $(DEFFLAGS) -c++ -python libirhvac.i
else
swig $(INCLUDES) $(DEFFLAGS) -c++ -python libirhvac.i
endif

clean :
rm -f *.o *.pyc *.cxx *.cpp
rm -rf swig-4.2.0
distclean :
rm -f *.o *.pyc libirhvac_wrap.cxx irhvac.py _irhvac.so
rm -rf swig-4.2.0


test : _irhvac.so
python test_lib.py

docker : swig-4.2.0/swig _irhvac.so

testdocker : swig-4.2.0/swig _irhvac.so
python test_lib.py

# Keep all intermediate files.
.SECONDARY:

# All the IR protocol object files.
PROTOCOL_OBJS = $(patsubst %.cpp,%.o,$(wildcard $(SRC_DIR)/ir_*.cpp))
PROTOCOLS = $(patsubst $(SRC_DIR)/%,%,$(PROTOCOL_OBJS))

# Common object files
COMMON_OBJ = libirhvac_wrap.o IRutils.o IRtimer.o IRsend.o IRrecv.o IRtext.o IRac.o $(PROTOCOLS)

# Common dependencies
COMMON_DEPS = $(SRC_DIR)/IRrecv.h $(SRC_DIR)/IRsend.h $(SRC_DIR)/IRtimer.h \
$(SRC_DIR)/IRutils.h $(SRC_DIR)/IRremoteESP8266.h \
$(SRC_DIR)/IRtext.h $(SRC_DIR)/i18n.h
# Common test dependencies
COMMON_TEST_DEPS = $(COMMON_DEPS) $(TEST_DIR)/IRsend_test.h

IRtext.o : $(SRC_DIR)/IRtext.cpp $(SRC_DIR)/IRtext.h $(SRC_DIR)/IRremoteESP8266.h $(SRC_DIR)/i18n.h $(SRC_DIR)/locale/*.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/IRtext.cpp

IRutils.o : $(SRC_DIR)/IRutils.cpp $(SRC_DIR)/IRutils.h $(SRC_DIR)/IRremoteESP8266.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/IRutils.cpp

IRsend.o : $(SRC_DIR)/IRsend.cpp $(SRC_DIR)/IRsend.h $(SRC_DIR)/IRremoteESP8266.h
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/IRsend.cpp

IRrecv.o : $(SRC_DIR)/IRrecv.cpp $(SRC_DIR)/IRrecv.h $(SRC_DIR)/IRremoteESP8266.h $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/IRrecv.cpp

libirhvac_wrap.o : libirhvac_wrap.cxx
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) $(PYTHONINCL) -c libirhvac_wrap.cxx

libirhvac_wrap.cxx :
swig $(INCLUDES) $(DEFFLAGS) -c++ -python libirhvac.i

_irhvac.so : $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,lib_irhvac.so -o _irhvac.so $(COMMON_OBJ)

swig-4.2.0/swig :
curl -s -L -o - http://downloads.sourceforge.net/project/swig/swig/swig-4.2.0/swig-4.2.0.tar.gz | tar xfz -
( cd swig-4.2.0; ./configure ; make )
# new specific targets goes above this line

$(objects) : %: $(COMMON_OBJ)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@

ir_%.o : $(SRC_DIR)/ir_%.h $(SRC_DIR)/ir_%.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/ir_$*.cpp

ir_%.o : $(SRC_DIR)/ir_%.cpp $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/ir_$*.cpp

%.o : %.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $*.cpp

%.o : $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h $(COMMON_DEPS) $(GTEST_HEADERS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/$*.cpp
26 changes: 26 additions & 0 deletions python/libirhvac.i
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
%module (package="pyhvac") irhvac
#define SWIGPYTHON_BUILTIN
%include <std_string.i>
%include "stdint.i"
%{
#include <vector>
#include "IRac.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
%}
%include <std_vector.i>
%template(VectorOfInt) std::vector<int>;
%typemap(out) std::vector<int> (PyObject* _outer) %{
// Allocate a PyList object of the requested size.
_outer = PyList_New($1.size());
// Populate the PyList. PyLong_FromLong converts a C++ "long" to a
// Python PyLong object.
for(int x = 0; x < $1.size(); x++) {
PyList_SetItem(_outer,x,PyLong_FromLong($1[x]));
}
$result = SWIG_Python_AppendOutput($result,_outer);
%}
%include <IRsend.h>
%include <IRremoteESP8266.h>
%include <IRac.h>

11 changes: 11 additions & 0 deletions python/test_lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import irhvac
ac=irhvac.IRac(4)

ac.next.protocol = irhvac.COOLIX
ac.next.mode = irhvac.opmode_t_kAuto
ac.next.degrees = 24
ac.sendAc()
assert ac.getTiming() == [4692, 4416, 552, 1656, 552, 552, 552, 1656, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 1656, 552, 552, 552, 1656, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 1656, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 552, 552, 552, 552, 552, 552, 552, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 1656, 552, 1656, 552, 5244, 4692, 4416, 552, 1656, 552, 552, 552, 1656, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 1656, 552, 552, 552, 1656, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 1656, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 552, 552, 552, 552, 552, 552, 552, 552, 1656, 552, 552, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 552, 1656, 552, 1656, 552, 1656, 552, 1656, 552, 1656, 552, 5244, 100000]
print("Success!")


13 changes: 13 additions & 0 deletions src/IRac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#else
using ::roundf;
#endif
#ifdef SWIGLIB
#include <vector>
extern std::vector<int> timingList;
#endif
#include "IRsend.h"
#include "IRremoteESP8266.h"
#include "IRtext.h"
Expand Down Expand Up @@ -73,6 +77,7 @@
#ifndef UNIT_TEST
#define OUTPUT_DECODE_RESULTS_FOR_UT(ac)
#else
#ifndef SWIGLIB
/* NOTE: THIS IS NOT A DOXYGEN COMMENT (would require ENABLE_PREPROCESSING-YES)
/// If compiling for UT *and* a test receiver @c IRrecv is provided via the
/// @c _utReceived param, this injects an "output" gadget @c _lastDecodeResults
Expand All @@ -98,6 +103,9 @@
} \
} \
}
#else
#define OUTPUT_DECODE_RESULTS_FOR_UT(ac)
#endif // SWIGLIB
#endif // UNIT_TEST

/// Class constructor
Expand Down Expand Up @@ -181,6 +189,11 @@ stdAc::state_t IRac::getState(void) { return next; }
/// @return A Ptr to a state containing the previously sent settings.
stdAc::state_t IRac::getStatePrev(void) { return _prev; }

#ifdef SWIGLIB
std::vector<int> IRac::getTiming(void) { return timingList; }
void IRac::resetTiming(void) { timingList.clear(); }
#endif

/// Is the given protocol supported by the IRac class?
/// @param[in] protocol The vendor/protocol type.
/// @return true if the protocol is supported by this class, otherwise false.
Expand Down
9 changes: 9 additions & 0 deletions src/IRac.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#else
#include <memory>
#endif
#ifdef SWIGLIB
#include <vector>
#endif
#include "IRremoteESP8266.h"
#include "ir_Airton.h"
#include "ir_Airwell.h"
Expand Down Expand Up @@ -107,15 +110,21 @@ class IRac {
static String swinghToString(const stdAc::swingh_t swingh);
stdAc::state_t getState(void);
stdAc::state_t getStatePrev(void);
#ifdef SWIGLIB
std::vector<int> getTiming(void);
void resetTiming(void);
#endif
bool hasStateChanged(void);
stdAc::state_t next; ///< The state we want the device to be in after we send
#ifdef UNIT_TEST
#ifndef SWIGLIB
/// @cond IGNORE
/// UT-specific
/// See @c OUTPUT_DECODE_RESULTS_FOR_UT macro description in IRac.cpp
std::shared_ptr<IRrecv> _utReceiver = nullptr;
std::unique_ptr<decode_results> _lastDecodeResults = nullptr;
/// @endcond
#endif
#else

private:
Expand Down
15 changes: 15 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#endif
#include "IRtimer.h"

#ifdef SWIGLIB
std::vector<int> timingList;
#endif

/// Constructor for an IRsend object.
/// @param[in] IRsendPin Which GPIO pin to use when sending an IR command.
/// @param[in] inverted Optional flag to invert the output. (default = false)
Expand Down Expand Up @@ -155,6 +159,11 @@ void IRsend::_delayMicroseconds(uint32_t usec) {
/// Ref:
/// https://www.analysir.com/blog/2017/01/29/updated-esp8266-nodemcu-backdoor-upwm-hack-for-ir-signals/
uint16_t IRsend::mark(uint16_t usec) {
#ifdef SWIGLIB
// std::cout << usec << " ";
timingList.push_back(usec);
return 1;
#else
// Handle the simple case of no required frequency modulation.
if (!modulation || _dutycycle >= 100) {
ledOn();
Expand Down Expand Up @@ -185,6 +194,7 @@ uint16_t IRsend::mark(uint16_t usec) {
elapsed = usecTimer.elapsed(); // Update & recache the actual elapsed time.
}
return counter;
#endif
}

/// Turn the pin (LED) off for a given time.
Expand All @@ -194,7 +204,12 @@ uint16_t IRsend::mark(uint16_t usec) {
void IRsend::space(uint32_t time) {
ledOff();
if (time == 0) return;
#ifdef SWIGLIB
// std::cout << time << " ";
timingList.push_back(time);
#else
_delayMicroseconds(time);
#endif
}

/// Calculate & set any offsets to account for execution times during sending.
Expand Down
21 changes: 18 additions & 3 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

#define __STDC_LIMIT_MACROS
#include <stdint.h>
#ifdef SWIGLIB
#include <vector>
#endif // SWIGLIB
#include "IRremoteESP8266.h"

// Originally from https://github.com/shirriff/Arduino-IRremote/
Expand All @@ -14,8 +17,14 @@

#if TEST || UNIT_TEST
#define VIRTUAL virtual
#ifdef SWIGLIB
#define VIRTUALMS
#else
#define VIRTUALMS virtual
#endif // SWIGLIB
#else
#define VIRTUAL
#define VIRTUALMS
#endif

// Constants
Expand Down Expand Up @@ -43,6 +52,11 @@ const uint32_t kDefaultMessageGap = 100000;
/// @note Not using "-1" as it may be a valid external temp
const float kNoTempValue = -100.0;

#ifdef SWIGLIB
// Global
extern std::vector<int> timingList;
#endif

/// Enumerators and Structures for the Common A/C API.
namespace stdAc {
/// Common A/C settings for A/C operating modes.
Expand Down Expand Up @@ -228,6 +242,7 @@ enum argo_ac_remote_model_t {
SAC_WREM3 // (2) ARGO WREM3 remote (touch buttons), bit-len vary by cmd
};

#ifndef SWIG
// Classes

/// Class for sending all basic IR protocols.
Expand All @@ -241,8 +256,8 @@ class IRsend {
void begin();
void enableIROut(uint32_t freq, uint8_t duty = kDutyDefault);
VIRTUAL void _delayMicroseconds(uint32_t usec);
VIRTUAL uint16_t mark(uint16_t usec);
VIRTUAL void space(uint32_t usec);
VIRTUALMS uint16_t mark(uint16_t usec);
VIRTUALMS void space(uint32_t usec);
int8_t calibrate(uint16_t hz = 38000U);
void sendRaw(const uint16_t buf[], const uint16_t len, const uint16_t hz);
void sendData(uint16_t onemark, uint32_t onespace, uint16_t zeromark,
Expand Down Expand Up @@ -917,5 +932,5 @@ class IRsend {
const uint16_t repeat, const uint16_t freq);
#endif // SEND_SONY
};

#endif // SWIG
#endif // IRSEND_H_