Skip to content

Commit 937e843

Browse files
frawauclaude
andauthored
IRremoteESP8266 in a python library (#2067)
Set things so that one can generate a stand alone library and access it via python. Remove duplicated code from SWIG file. Makefile now download and install locally SWIG 4.2.0. Added a simple test to make sure the lib builds and produce some reasonable output. Add the test to the UnitTest.yml workflow definition. Install swig when using docker. So rearrange make file to support that. * Changed PYTHONLIB to SWIGLIB in ifdef's. This way, it is no longer Python specifics since one could use swig create libraries for other languages. * Fix cpplint build/include_what_you_use for vector in IRsend.cpp * Fix SWIG typemap for compatibility with SWIG 4.3+ SWIG_Python_AppendOutput gained a third argument in SWIG 4.3. Replace the direct internal call with a simple $result = _outer assignment (getTiming returns a single value, no appending needed). Also fix signed/unsigned comparison in the loop index. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 630ce00 commit 937e843

File tree

8 files changed

+422
-3
lines changed

8 files changed

+422
-3
lines changed

.github/workflows/UnitTests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jobs:
1313
run: (cd tools; make all)
1414
- name: Run tools unit tests
1515
run: (cd tools; make run_tests)
16+
- name: Build swig extension and run simple test
17+
run: (cd python; make testdocker)
1618

1719
Unit_Tests:
1820
runs-on: ubuntu-latest

python/Makefile

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# SYNOPSIS:
2+
#
3+
# make [all] - makes everything.
4+
# make TARGET - makes the given target.
5+
# make run_tests - makes everything and runs all test
6+
# make run-% - run specific test file (exclude .py)
7+
# replace % with given test file
8+
# make clean - removes all files generated by make.
9+
10+
# Please tweak the following variable definitions as needed by your
11+
# project, except GTEST_HEADERS, which you can use in your own targets
12+
# but shouldn't modify.
13+
14+
ifeq (,$(wildcard ./.dockerenv))
15+
SWIGTYPE = local
16+
else
17+
SWIGTYPE = global
18+
endif
19+
20+
# Where to find user code.
21+
SRC_DIR = ../src
22+
23+
# Where to find test code.
24+
TEST_DIR = ../test
25+
26+
INCLUDES = -I$(SRC_DIR) -I$(TEST_DIR)
27+
DEFFLAGS = -DUNIT_TEST -DSWIGLIB
28+
# Flags passed to the preprocessor.
29+
# Set Google Test's header directory as a system directory, such that
30+
# the compiler doesn't generate warnings in Google Test headers.
31+
CPPFLAGS += -D_IR_LOCALE_=en-AU -fPIC $(DEFFLAGS)
32+
33+
# Flags passed to the C++ compiler.
34+
CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11
35+
36+
PYTHONINCL = $(shell python3-config --includes)
37+
38+
objects = $(patsubst %.cpp,%,$(wildcard *.cpp))
39+
40+
all : _irhvac.so
41+
42+
library : $(objects)
43+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,lib_irhvac.so -o _irhvac.so $(COMMON_OBJ)
44+
45+
swig : libirhvac_wrap.cxx
46+
ifneq (,$(wildcard /.dockerenv))
47+
SWIG_LIB=$(shell realpath -qe swig-4.2.0/Lib) ./swig-4.2.0/swig $(INCLUDES) $(DEFFLAGS) -c++ -python libirhvac.i
48+
else
49+
swig $(INCLUDES) $(DEFFLAGS) -c++ -python libirhvac.i
50+
endif
51+
52+
clean :
53+
rm -f *.o *.pyc *.cxx *.cpp
54+
rm -rf swig-4.2.0
55+
distclean :
56+
rm -f *.o *.pyc libirhvac_wrap.cxx irhvac.py _irhvac.so
57+
rm -rf swig-4.2.0
58+
59+
60+
test : _irhvac.so
61+
python test_lib.py
62+
63+
docker : swig-4.2.0/swig _irhvac.so
64+
65+
testdocker : swig-4.2.0/swig _irhvac.so
66+
python test_lib.py
67+
68+
# Keep all intermediate files.
69+
.SECONDARY:
70+
71+
# All the IR protocol object files.
72+
PROTOCOL_OBJS = $(patsubst %.cpp,%.o,$(wildcard $(SRC_DIR)/ir_*.cpp))
73+
PROTOCOLS = $(patsubst $(SRC_DIR)/%,%,$(PROTOCOL_OBJS))
74+
75+
# Common object files
76+
COMMON_OBJ = libirhvac_wrap.o IRutils.o IRtimer.o IRsend.o IRrecv.o IRtext.o IRac.o $(PROTOCOLS)
77+
78+
# Common dependencies
79+
COMMON_DEPS = $(SRC_DIR)/IRrecv.h $(SRC_DIR)/IRsend.h $(SRC_DIR)/IRtimer.h \
80+
$(SRC_DIR)/IRutils.h $(SRC_DIR)/IRremoteESP8266.h \
81+
$(SRC_DIR)/IRtext.h $(SRC_DIR)/i18n.h
82+
# Common test dependencies
83+
COMMON_TEST_DEPS = $(COMMON_DEPS) $(TEST_DIR)/IRsend_test.h
84+
85+
IRtext.o : $(SRC_DIR)/IRtext.cpp $(SRC_DIR)/IRtext.h $(SRC_DIR)/IRremoteESP8266.h $(SRC_DIR)/i18n.h $(SRC_DIR)/locale/*.h
86+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/IRtext.cpp
87+
88+
IRutils.o : $(SRC_DIR)/IRutils.cpp $(SRC_DIR)/IRutils.h $(SRC_DIR)/IRremoteESP8266.h
89+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/IRutils.cpp
90+
91+
IRsend.o : $(SRC_DIR)/IRsend.cpp $(SRC_DIR)/IRsend.h $(SRC_DIR)/IRremoteESP8266.h
92+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/IRsend.cpp
93+
94+
IRrecv.o : $(SRC_DIR)/IRrecv.cpp $(SRC_DIR)/IRrecv.h $(SRC_DIR)/IRremoteESP8266.h $(GTEST_HEADERS)
95+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/IRrecv.cpp
96+
97+
libirhvac_wrap.o : libirhvac_wrap.cxx
98+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) $(PYTHONINCL) -c libirhvac_wrap.cxx
99+
100+
libirhvac_wrap.cxx :
101+
swig $(INCLUDES) $(DEFFLAGS) -c++ -python libirhvac.i
102+
103+
_irhvac.so : $(COMMON_OBJ)
104+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -shared -Wl,-soname,lib_irhvac.so -o _irhvac.so $(COMMON_OBJ)
105+
106+
swig-4.2.0/swig :
107+
curl -s -L -o - http://downloads.sourceforge.net/project/swig/swig/swig-4.2.0/swig-4.2.0.tar.gz | tar xfz -
108+
( cd swig-4.2.0; ./configure ; make )
109+
# new specific targets goes above this line
110+
111+
$(objects) : %: $(COMMON_OBJ)
112+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
113+
114+
ir_%.o : $(SRC_DIR)/ir_%.h $(SRC_DIR)/ir_%.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
115+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/ir_$*.cpp
116+
117+
ir_%.o : $(SRC_DIR)/ir_%.cpp $(GTEST_HEADERS)
118+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/ir_$*.cpp
119+
120+
%.o : %.cpp $(COMMON_DEPS) $(GTEST_HEADERS)
121+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $*.cpp
122+
123+
%.o : $(SRC_DIR)/%.cpp $(SRC_DIR)/%.h $(COMMON_DEPS) $(GTEST_HEADERS)
124+
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(SRC_DIR)/$*.cpp

python/libirhvac.i

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
%module (package="pyhvac") irhvac
2+
#define SWIGPYTHON_BUILTIN
3+
%include <std_string.i>
4+
%include "stdint.i"
5+
%{
6+
#include <vector>
7+
#include "IRac.h"
8+
#include "IRremoteESP8266.h"
9+
#include "IRsend.h"
10+
%}
11+
%include <std_vector.i>
12+
%template(VectorOfInt) std::vector<int>;
13+
%typemap(out) std::vector<int> (PyObject* _outer) %{
14+
// Allocate a PyList object of the requested size.
15+
_outer = PyList_New($1.size());
16+
// Populate the PyList. PyLong_FromLong converts a C++ "long" to a
17+
// Python PyLong object.
18+
for(size_t x = 0; x < $1.size(); x++) {
19+
PyList_SetItem(_outer, x, PyLong_FromLong($1[x]));
20+
}
21+
$result = _outer;
22+
%}
23+
%include <IRsend.h>
24+
%include <IRremoteESP8266.h>
25+
%include <IRac.h>
26+

python/test_lib.py

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
import irhvac
2+
3+
ac = irhvac.IRac(4)
4+
5+
ac.next.protocol = irhvac.COOLIX
6+
ac.next.mode = irhvac.opmode_t_kAuto
7+
ac.next.degrees = 24
8+
ac.sendAc()
9+
assert ac.getTiming() == [
10+
4692,
11+
4416,
12+
552,
13+
1656,
14+
552,
15+
552,
16+
552,
17+
1656,
18+
552,
19+
1656,
20+
552,
21+
552,
22+
552,
23+
552,
24+
552,
25+
1656,
26+
552,
27+
552,
28+
552,
29+
552,
30+
552,
31+
1656,
32+
552,
33+
552,
34+
552,
35+
552,
36+
552,
37+
1656,
38+
552,
39+
1656,
40+
552,
41+
552,
42+
552,
43+
1656,
44+
552,
45+
552,
46+
552,
47+
1656,
48+
552,
49+
1656,
50+
552,
51+
1656,
52+
552,
53+
1656,
54+
552,
55+
552,
56+
552,
57+
1656,
58+
552,
59+
1656,
60+
552,
61+
1656,
62+
552,
63+
552,
64+
552,
65+
552,
66+
552,
67+
552,
68+
552,
69+
552,
70+
552,
71+
1656,
72+
552,
73+
552,
74+
552,
75+
552,
76+
552,
77+
1656,
78+
552,
79+
1656,
80+
552,
81+
1656,
82+
552,
83+
552,
84+
552,
85+
552,
86+
552,
87+
552,
88+
552,
89+
552,
90+
552,
91+
552,
92+
552,
93+
552,
94+
552,
95+
552,
96+
552,
97+
552,
98+
552,
99+
1656,
100+
552,
101+
1656,
102+
552,
103+
1656,
104+
552,
105+
1656,
106+
552,
107+
1656,
108+
552,
109+
5244,
110+
4692,
111+
4416,
112+
552,
113+
1656,
114+
552,
115+
552,
116+
552,
117+
1656,
118+
552,
119+
1656,
120+
552,
121+
552,
122+
552,
123+
552,
124+
552,
125+
1656,
126+
552,
127+
552,
128+
552,
129+
552,
130+
552,
131+
1656,
132+
552,
133+
552,
134+
552,
135+
552,
136+
552,
137+
1656,
138+
552,
139+
1656,
140+
552,
141+
552,
142+
552,
143+
1656,
144+
552,
145+
552,
146+
552,
147+
1656,
148+
552,
149+
1656,
150+
552,
151+
1656,
152+
552,
153+
1656,
154+
552,
155+
552,
156+
552,
157+
1656,
158+
552,
159+
1656,
160+
552,
161+
1656,
162+
552,
163+
552,
164+
552,
165+
552,
166+
552,
167+
552,
168+
552,
169+
552,
170+
552,
171+
1656,
172+
552,
173+
552,
174+
552,
175+
552,
176+
552,
177+
1656,
178+
552,
179+
1656,
180+
552,
181+
1656,
182+
552,
183+
552,
184+
552,
185+
552,
186+
552,
187+
552,
188+
552,
189+
552,
190+
552,
191+
552,
192+
552,
193+
552,
194+
552,
195+
552,
196+
552,
197+
552,
198+
552,
199+
1656,
200+
552,
201+
1656,
202+
552,
203+
1656,
204+
552,
205+
1656,
206+
552,
207+
1656,
208+
552,
209+
5244,
210+
100000,
211+
]
212+
print("Success!")

0 commit comments

Comments
 (0)