diff --git a/.gitignore b/.gitignore index d8a91fef..1bfc589d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.o *.pyc *.log +.idea /openzwave/ build/ dists/ @@ -50,6 +51,7 @@ debian/debhelper-build-stamp debian/python3-openzwave/ pybind lib.txt +log.txt pyozw.sqlite venv2/ venv3/ diff --git a/.travis.yml b/.travis.yml index 37c3c296..0b787937 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -language: cpp +language: python sudo: required python: - '3.5' @@ -6,9 +6,13 @@ env: matrix: - DOCKER_BASE=ubuntu:latest - DOCKER_BASE=debian:latest + - DOCKER_BASE=i386/ubuntu:xenial + #~ - DOCKER_BASE=arm32v7/ubuntu:xenial + #~ - DOCKER_BASE=arm64v8/ubuntu:xenial + #~ - DOCKER_BASE=resin/rpi-raspbian:latest - DOCS="true" global: - - secure: "ZSZRTtbNDT6nCuLp3HSMexxEzN01wqFjBkSkx9fGeUfXWeWiGNGc3Gsqd1U+SGXRYSqcmF7czr2WF+r1Mtz+/dbH8pYT6c5mQg4unJyljVFwPmv846Rg6IIRfn4sV3gr4FAN2fRi2Sm50uat9ZOJ+27o5+PmpZ5/LOdGHJ7pUVyimrkejn3cfOGAU7s6lnkUs5wjIfLBHs3NKAbSp2eu8YgxduwrvZOaY9VOx5uUjKLeY6fBtIzJGKI1b5Ef1JkumGDuWJBe14CpYj7cYSMexmd2Gsrn4RzLfNcH9dss4SW8uEcV4K7LxLJ1kXCGSr8Pq0l4ei/ibvh/05RgQap7uQ02Y5J7SDhUjfO0HqoazvosqTMWlWNTUoR3OFOwuV2MqjcVqWr/2DA7rXWx6ZhWjKmb7X8R30fa49D+HaRCs+de/zpeeUqTSQaTRPpC72hG56ToxbHo2/nDQoPEXZrcqrDni7fdNi8IwicA6fowZE3+LQ5zY0u2nixt8Kp9U29QG079xA7CBwWiC8jq1+Cc05qPpPT0iaTlZd9XPFVZEvtEWRPGNC/YINIJpfprQ1tnaANNGCCUpPDrdzld+yEI8KTC1uCICjmi9hyQWBgkpw9U3Q+PlBqOVdXYPCn7gnmFRkZMLimOqtSAjd0hDPAyZ83k5kGoR/ZBxzwZ3f3Nkfc=" + - secure: "LdXdleVnh5s6HRPWLh3LcYo+s2IpvxwjFOQSJdMM1/svpstBu+pqAy6y6ivn4u7RUgG1Hva+iImMmqoBw4MUl+CTvK1RTLsOFFa0z37XSdWJbHSA+SmH9Dith1iHjaHTnkMNRaJugfJoLm2RXsii4ksMZcncm0gQLChyH+kxzX+ytoz8ofKk6f8zKqa+8YYhTlsV+BtnaEJOli22FKmLI8glOYiJpJj9UG8xQkwzNlIxR0PNZxvXnfVLeIw4sF9R3h6fkM/PZGbEfn1roZYDsdepl6SwumfmY+gOB74Ze7oObeJjmXA1HC8NSrsivIDB+gfAzKE01Jk2LyNZ+T2u7Zlqjf9pV0HhkYuBhc38BkpeBKkMKliJwuSIwEdsGWR71rC7VmegSbKp/I3Ev3oWy3h0k/J/W4SIxhN4mc8DAhaIC5TPdMHHTBSWyh494PEjX5zrinq4w6K7qjWpUB6rEUpHTHIE/F5f46QRTwFb5bhusIH8Hjo7GceEtYy1h8vGJ16GnAqvvrBJBU5QKCSfJicMiOUPELl3iD86vOdrJyYiiU+jALvgQH70D7KA9igIGRjmOdv71D09bEOVAYSNOaBsiCtyZqyx8kDMSETJ92VwhLO/aKazoGqlgiI8bEqSHA7Tjah6vyeTdnZeWRg7Fh2RM4W1T7lkXqzICNbUdW0=" services: - docker before_install: @@ -16,7 +20,8 @@ before_install: docker pull ${DOCKER_BASE}; fi - if [[ "${DOCS}" == "true" ]]; then - sudo apt install -y libudev-dev; + sudo apt-get update; + sudo make common-deps; fi script: - if [[ "${DOCKER_BASE}x" != "x" ]]; then @@ -24,14 +29,11 @@ script: fi - if [[ "${DOCS}" == "true" ]]; then set -e; - make venv3; - source venv3/bin/activate; - pip install doctr; - make install-api doc-deps; + make doc-deps; + make install-api; cd docs; make html; cd ..; - export GIT_AUTHOR_NAME=$(git --no-pager show -s --format='%an' HEAD); - export GIT_AUTHOR_EMAIL=$(git --no-pager show -s --format='%ae' HEAD); + pip3 install doctr; doctr deploy --built-docs docs/_build/html .; fi diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 69eefc0b..1b504fd0 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,77 @@ Changelog ********* +python_openzwave 0.4.18.x: + * Fix python 2.7/appveyor + + * Add serial port auto-detection + +python_openzwave 0.4.17.x: + * Add wheels for Windows + +python_openzwave 0.4.16.x: + * Fix appveyor build for windows + +python_openzwave 0.4.15.x: + * Update embeded package + +python_openzwave 0.4.14.x: + * Use Cython 0.28.6 + + * Update embeded package + +python_openzwave 0.4.12.x: + * Improve support Windows + + * COMMAND_CLASS_ZWAVE_PLUS_INFO renamed to + COMMAND_CLASS_ZWAVEPLUS_INFO + + * Update thermostat + + * Update embeded package + +python_openzwave 0.4.11.x: + * Update embeded package + +python_openzwave 0.4.10.x: + * Improve support Windows in pip + + * Improve tests Windows + + * Update contructors for scenes and groups + +python_openzwave 0.4.9.x: + * Improve support Windows in pip + + * Update tests + +python_openzwave 0.4.6.x: + * First try to support Windows in pip + +python_openzwave 0.4.5.x: + * Fix bug in node statistics and add test. + + * Update Makefile to build flavor dev + + * Update pyozw_check. + + * Update default flavor : check cython is here before choosing + shared + + * Fix controller.update_ozw_config when directory isn't writable + +python_openzwave 0.4.4.x: + * Add new options to pyozw_check to list nodes on network. + +python_openzwave 0.4.3.x: + * Fix bug in default flavor. + +python_openzwave 0.4.1.x: + * Update the default flavor : try to use a precompiled library. + If can't find one, use the embeded package. + + * Add method to controller to get new config from github. + python_openzwave 0.4.0.x: * New installation process via pip diff --git a/DEVEL.txt b/DEVEL.txt index a0382730..f2d8f06b 100644 --- a/DEVEL.txt +++ b/DEVEL.txt @@ -5,88 +5,44 @@ Developers information How to develop for python-openzwave =================================== -Get the sources +Fork the project on Github. - git clone https://github.com/OpenZWave/python-openzwave +Get the sources : + + git clone https://github.com/yourname/python-openzwave You can install all the dependances to develop for python-openzwave using the command : sudo make developer-deps -You must now install python-openzwave in develop mode +You must now install python-openzwave in develop mode. Depending on +which python version you prefer, use : + + make venv2-dev - make develop +or -Your password will be asked (by sudo) for installing eggs in your -local directory. + make venv2-dev + +Keep in mind that your updates must be python 2 / python 3 compatible. Develop, test, debug, test, ... :) Update the documentation if needed. You surely found the documentation useful, so please keep it up to date. -You can create an account on travis or docker to run the tests. - -At last but not least, submit your request. - - -How to develop for libopenzwave (was python-openzwave-lib) -========================================================== - -After updating the pyx, you need to reinstall it. Otherwise, your -changes will not be applied : - - make develop - - -Tests -===== - -First, install the dependances : - - sudo make tests-deps - -To launch all the tests suite (about 140 tests), use the following -command : +It a good idea to add automatic tests. - make tests +Launch the full test suite (for python 2 and python 3) : -To launch particular tests : + make venv-tests - nosetests --verbosity=2 tests/api/test_controller_command.py +At last but not least, submit your request with the result of tests in +the comment. -Some tests need manual operations (ie to add a node, to remove one, -...). For example, to test the remove node, use : - - export MANUALSKIP='False' && nosetests --verbosity=2 tests/api/test_controller_command.py -m test_150 && unset MANUALSKIP - test_150_command_remove_node_and_wait_for_user (tests.api.test_controller_command.TestControllerCommand) ... ok - - ---------------------------------------------------------------------- - Ran 1 test in 16.031s - - OK - -You should push the inclusion button of the node before the end of the -test. - -Some tests don't need a ZWave Stick to be launched, so they can be run -on the autobuilders (travis, docker, ...). Place them in the autobuild -directory. - -Travis-ci, Docker Hub, nosetests and pylint are used to test quality -of code. There reports are here : - - * Docker : https://registry.hub.docker.com/u/bibi21000/python- - openzwave/ - - * Travis : https://travis-ci.org/bibi21000/python-openzwave - - * Nosetests report - - * Coverage report - - * Pylint report +If you don't follow the previous steps, your PR will be refused or +letting in pending state until I've got time to test it. Documentation @@ -96,97 +52,7 @@ First, install the dependances : sudo make doc-deps -Documentation is managed with sphinx. Don't utpdate txt files (README, -INSTALL, ...), update the RST sources in docs. Use the following -commands to generate all docs files (txt, html and joomla) - -You need to have installed python-openzwave (in either develop or -install mode) before generating the documentation. - - make docs - - -Static vs dynamic (or shared) -============================= - -The openzwave (c++) lib needs to run as a singleton : it means that it -MUST have only one instance of the manager running on your computer. - -There is 2 ways of linking libraries with a program : - - * static : includes a copy of the library in your binary program. - This means that your program has its own instance of the library. - This the way the install.sh runs. So you CAN'T have another - program (like the control-panel) running when using the python- - openzwave library - - * dynamic or shared : includes a link to the library in your - binary program. This means that your program share the library - with other programs. In this case, the instance is owned directly - by the library. This the way the debian package works. So you CAN - have another program running when using the python-openzwave - library. Of course, this program MUST use the shared library too. - - -About sudo -========== - -If you are like me and don't like root (and sudo), you can use the -following tip to install packages via pip : - -Look at your python local library, it should looks like : - - ls -lisa /usr/local/lib/python2.7/dist-packages/ - total 2428 - 1445174 12 drwxrwsr-x 115 root staff 12288 avril 9 21:35 . - 1445172 4 drwxrwsr-x 4 root staff 4096 mai 2 2014 .. - 1457164 4 drwxr-sr-x 5 root staff 4096 nov. 26 2013 actdiag - 1715480 4 drwxr-sr-x 2 root staff 4096 nov. 26 2013 actdiag-0.5.1.egg-info - 1457163 4 -rw-r--r-- 1 root staff 1004 nov. 26 2013 actdiag_sphinxhelper.py - 1457172 4 -rw-r--r-- 1 root staff 620 nov. 26 2013 actdiag_sphinxhelper.pyc - .... - -So, add your common user to the staff group : - - sudo usermod -a -G staff userName - -Add the write right to the group staff - - sudo chmod -Rf g+w /usr/local/lib/python2.7/dist-packages/ - -And now, it's time log off and log on. Groups are checked when you -open the session. - -You can now install your packages without sudo. - - -Python3 and virtualenv -====================== - -Python 3 is actually not supported. - -A branch (python3) has been created with a special Dockerfile. It -build python-openzwave and launch some tests. This branch is -automatically merged from master at "make commit". - -So please, do not directly push under python3 branch. Make your -developments under master or another branch. - -It's important for me have python2/python3 compatibilty in the master -branch. cython can help for this : -http://docs.cython.org/src/tutorial/strings.html - -The Makefile sill try to automatically configure your version of -python (running python --version). - -If you want to install python-openzwave in a python virtual -environnement, you should use something like : - - make VIRTUAL_ENV=/path/to/my/venv ... - -If you use python 3 and your python executable is called python3 : - - make PYTHON_EXEC=python3 ... +Documentation is managed with sphinx. -You can also put these variables in a CONFIG.make file instead of -passing them to the command line +Don't update txt and rst files (README, INSTALL, ...) in the root +directory, update the RST sources in docs. diff --git a/Dockerfile b/Dockerfile index a2ce3d75..0fa0cc47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,15 @@ FROM ubuntu:latest MAINTAINER bibi21000 ENV PYOZW_DOCKER 1 -RUN apt-get update && apt-get dist-upgrade -y -RUN apt-get install -y --no-install-recommends make sudo apt-utils +RUN apt-get update && apt-get dist-upgrade -y >/dev/null +RUN apt-get install -y --no-install-recommends make sudo apt-utils >/dev/null ADD . /home/pyozw WORKDIR /home/pyozw -RUN ls -WORKDIR /home/pyozw/ -RUN make docker-deps -RUN make openzwave.gzip +RUN make docker-deps >/dev/null +RUN make openzwave.gzip >/dev/null RUN make venv-dev-autobuild-tests #RUN make venv-pypi-autobuild-tests +#RUN apt-get install --force-yes -y pkg-config >/dev/null +#RUN make venv-git_shared-autobuild-tests +#RUN apt-get remove --force-yes -y pkg-config >/dev/null RUN make venv-pypilive-autobuild-tests diff --git a/INSTALL_WIN.rst b/INSTALL_WIN.rst index 8c102ef1..6ced83fc 100755 --- a/INSTALL_WIN.rst +++ b/INSTALL_WIN.rst @@ -5,51 +5,183 @@ Installing python-openzwave on Windows ====================================== -This HOW-TO is for 0.4.X. +Install Microsoft tools +======================= -It should be possible to make it pip friendly. Need a command line to build openzwave c++ lib. +This package use MSBuild.exe to build openzwave code. -How To Build python-openzwave on Windows with VS2015 -==================================================== +You can find it in Visual Studio 2017 or Visual Studio 2015. -Assuming Python 3.5 is set in PATH -Assuming your python environment has pip, cython, setuptools +It's also possible to get it as a separate package. +Only release 14.0 and 15.0 of Microsft Build Tools are tested. -Get sources ------------ +You nust use the C++ compiler used to build your version of python : https://wiki.python.org/moin/WindowsCompilers -.. code-block:: bash - git clone https://github.com/openzwave/python-openzwave.git +Install other tools +=================== - cd python-openzwave - git clone git://github.com/OpenZWave/open-zwave.git openzwave +You need git to clone the repository and python (32 bits or 64 bits). Add it to your PATH. + +Install dependencies : + + - for python 2.7 : - cd openzwave - git checkout Dev - cd .. - git checkout + .. code-block:: bash + (venvX) pip install Cython six Louie -Build open-zwave ----------------- + - for python 3 : -Open openzwave/cpp/build/windows/vs2010/OpenZWave.sln in Visual Studio + .. code-block:: bash -When asked, accept the project upgrade to VS2015 + (venvX) pip install Cython six PyDispatcher -Build Win32|Release +clone repositories +================== +Clone python-openzwave: + + +.. code-block:: bash -Build python_openzwave ----------------------- + git clone https://github.com/OpenZWave/python-openzwave.git -From a Command Prompt, install it : +And clone open-zwave inside python-openzwave : .. code-block:: bash - python setup install --dev + cd python-openzwave + git clone https://github.com/OpenZWave/open-zwave.git openzwave + +It's mandatory to clone the previous repository in a directory called openzwave (not open-zwave) + +Visual studio +============= + +Copy vs2010 in a new directory vs2017 (or vs2015 depending of which Visual Studio you use) : + +.. code-block:: bash -Reference for 0.3.X : https://github.com/OpenZWave/python-openzwave/issues/53 + xcopy openzwave\cpp\build\windows\vs2010 openzwave\cpp\build\windows\vs2017 /s /e /h + +Open the project (openzwave\cpp\build\windows\vs2017\OpenZWave.sln) in your Visual Studio. +If you want to build for 64bits, add a new target for it. And finally close it. + +Python-openzwave +================ + +Build and install python-openzwave : + + .. code-block:: bash + + python setup.py install --flavor=dev + + .. code-block:: bash + + sysargv ['setup.py', 'install'] + thon setup.py install --flavor=dev + Requirement already satisfied: Cython in c:\program files (x86)\python36-32\lib\site-packages + {'name': 'libopenzwave', 'sources': ['src-lib/libopenzwave/libopenzwave.pyx'], 'include_dirs': ['openzwave/cpp/src', 'openzwave + /cpp/src/value_classes', 'openzwave/cpp/src/platform', 'openzwave/cpp/build/windows', 'src-lib/libopenzwave', 'openzwave/cpp/bu + ild/windows/vs2017/Release/'], 'define_macros': [('PY_LIB_VERSION', '0.4.4'), ('PY_SSIZE_T_CLEAN', 1), ('PY_LIB_FLAVOR', 'dev') + , ('PY_LIB_BACKEND', 'cython')], 'libraries': ['setupapi', 'msvcrt', 'ws2_32', 'dnsapi'], 'extra_objects': ['openzwave/cpp/buil + d/windows/vs2017/Release//OpenZWave.lib'], 'extra_compile_args': [], 'extra_link_args': [], 'language': 'c++'} + ['six', 'PyDispatcher>=2.0.5', 'Cython'] + Requirement already satisfied: Cython in c:\program files (x86)\python36-32\lib\site-packages + running install + flavor --flavor=dev c:\program files (x86)\python36-32\lib\site-packages + running build_openzwave + Found MSBuild.exe : c:/Program Files (x86)/Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe + Found arch : Win32 wave + Found Visual Studio project : vs2017 (x86)/Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe + Found build path : openzwave/cpp/build/windows/vs2017/Release/ + ... + ... + byte-compiling C:\Program Files (x86)\Python36-32\Lib\site-packages\python_openzwave\scripts\__init__.py to __init__.cpython-36 + .pyc + running install_egg_info + running egg_info + writing python_openzwave.egg-info\PKG-INFO + writing dependency_links to python_openzwave.egg-info\dependency_links.txt + writing entry points to python_openzwave.egg-info\entry_points.txt + ================================================================ + .\scripts\allusers.bat + this script is executed for all users + delete/rename it if you dont need it + ================================================================ + Page de codes active�: 437 + +And finally, test it : + + .. code-block:: bash + + pyozw_check -l -d COM2 -t 30 + + .. code-block:: bash + + ------------------------------------------------------------------------------- + Define options for device COM2 + Start network + Wait for network awake (30s) + ------------------------------------------------------------------------------- + Network is awaked. Talk to controller. + Get python_openzwave version : 0.4.4 + Get python_openzwave config version : Original Z-Wave 2.78 + Get python_openzwave flavor : dev + Get openzwave version : 1.4.2942 + Get config path : C:\Program Files\Python36\lib\site-packages\python_openzwave\ozw_config + Controller capabilities : {'primaryController', 'staticUpdateController'} + Controller node capabilities : {'listening', 'primaryController', 'beaming', 'staticUpdateController'} + Nodes in network : 4 + ------------------------------------------------------------------------------- + Wait for network ready (30s) + ------------------------------------------------------------------------------- + Network is ready. Get nodes + ------------------------------------------------------------ + 1 - Name : ( Location : ) + 1 - Ready : True / Awake : True / Failed : False + 1 - Manufacturer : Aeotec ( id : 0x0086 ) + 1 - Product : DSA02203 Z-Stick S2 ( id : 0x0001 / type : 0x0002 / Version : 3) + 1 - Command classes : set() + 1 - Capabilities : {'listening', 'primaryController', 'beaming', 'staticUpdateController'} + 1 - Neighbors : {4} / Power level : None + 1 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 2 - Name : ( Location : ) + 2 - Ready : True / Awake : True / Failed : False + 2 - Manufacturer : ( id : 0x0000 ) + 2 - Product : ( id : 0x0000 / type : 0x0000 / Version : 2) + 2 - Command classes : set() + 2 - Capabilities : {'listening', 'routing'} + 2 - Neighbors : {3} / Power level : None + 2 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 3 - Name : ( Location : ) + 3 - Ready : False / Awake : True / Failed : True + 3 - Manufacturer : ( id : 0x0000 ) + 3 - Product : ( id : 0x0000 / type : 0x0000 / Version : 3) + 3 - Command classes : set() + 3 - Capabilities : {'listening', 'routing', 'beaming'} + 3 - Neighbors : set() / Power level : None + 3 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 4 - Name : ( Location : ) + 4 - Ready : True / Awake : True / Failed : False + 4 - Manufacturer : GreenWave ( id : 0x0099 ) + 4 - Product : PowerNode 6 port ( id : 0x0004 / type : 0x0003 / Version : 4) + 4 - Command classes : {'COMMAND_CLASS_MANUFACTURER_SPECIFIC', 'COMMAND_CLASS_ASSOCIATION', 'COMMAND_CLASS_NO_OPERATION', 'COMM + AND_CLASS_VERSION', 'COMMAND_CLASS_SWITCH_BINARY', 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 'COMMAND_CLASS_CRC_16_ENCAP', 'COMMA + ND_CLASS_PROTECTION', 'COMMAND_CLASS_CONFIGURATION', 'COMMAND_CLASS_BASIC', 'COMMAND_CLASS_METER', 'COMMAND_CLASS_SWITCH_ALL'} + 4 - Capabilities : {'listening', 'routing', 'beaming'} + 4 - Neighbors : {1} / Power level : None + 4 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + Driver statistics : {'SOFCnt': 49, 'ACKWaiting': 0, 'readAborts': 0, 'badChecksum': 0, 'readCnt': 49, 'writeCnt': 46, 'CANCnt': + 0, 'NAKCnt': 1, 'ACKCnt': 30, 'OOFCnt': 0, 'dropped': 17, 'retries': 0, 'callbacks': 0, 'badroutes': 0, 'noack': 4, 'netbusy': + 0, 'nondelivery': 0, 'routedbusy': 0, 'broadcastReadCnt': 0, 'broadcastWriteCnt': 9} + ------------------------------------------------------------ + Stop network + Exit diff --git a/Makefile b/Makefile index 353ec227..9bb1a49b 100644 --- a/Makefile +++ b/Makefile @@ -157,7 +157,7 @@ endif ifeq (${python_version_major},3) apt-get install --force-yes -y cython3 endif - + ci-deps: apt-get install --force-yes -y python-pip python-dev python-docutils python-setuptools python-virtualenv -apt-get install --force-yes -y python3-pip python3-docutils python3-dev python3-setuptools @@ -182,7 +182,7 @@ tests-deps: doc-deps: -apt-get install --force-yes -y python-sphinx - ${PIP_EXEC} install sphinxcontrib-blockdiag sphinxcontrib-actdiag sphinxcontrib-nwdiag sphinxcontrib-seqdiag + ${PIP_EXEC} install cython sphinxcontrib-blockdiag sphinxcontrib-actdiag sphinxcontrib-nwdiag sphinxcontrib-seqdiag pip-deps: #${PIP_EXEC} install docutils @@ -197,18 +197,18 @@ clean-docs: -rm -Rf docs/pdf docs: clean-docs - -mkdir -p docs/html/nosetests - -mkdir -p docs/html/coverage - -mkdir -p docs/html/pylint - -mkdir -p docs/joomla/nosetests - -mkdir -p docs/joomla/coverage - -mkdir -p docs/joomla/pylint + #-mkdir -p docs/html/nosetests + #-mkdir -p docs/html/coverage + #-mkdir -p docs/html/pylint + #-mkdir -p docs/joomla/nosetests + #-mkdir -p docs/joomla/coverage + #-mkdir -p docs/joomla/pylint #${NOSE_EXEC} $(NOSEOPTS) $(NOSECOVER) tests/ #${NOSE_EXEC} $(NOSEOPTS) tests/ - -cp docs/html/nosetests/* docs/joomla/nosetests - -cp docs/html/coverage/* docs/joomla/coverage + #-cp docs/html/nosetests/* docs/joomla/nosetests + #-cp docs/html/coverage/* docs/joomla/coverage #-$(PYLINT) --output-format=html $(PYLINTOPTS) src-lib/libopenzwave/ src-api/openzwave/ src-manager/pyozwman/ src-web/pyozwweb/>docs/html/pylint/report.html - -cp docs/html/pylint/* docs/joomla/pylint/ + #-cp docs/html/pylint/* docs/joomla/pylint/ cd docs && $(MAKE) docs cp docs/README.rst README.rst cp docs/INSTALL_REPO.rst . @@ -220,12 +220,12 @@ docs: clean-docs cp docs/_build/text/CHANGELOG.txt . cp docs/_build/text/DEVEL.txt . cp docs/_build/text/EXAMPLES.txt . - cp -Rf docs/_build/html/* docs/html/ - cp -Rf docs/_build/joomla/* docs/joomla/ + #cp -Rf docs/_build/html/* docs/html/ + #cp -Rf docs/_build/joomla/* docs/joomla/ @echo @echo "Documentation finished." -install-lib: build +install-lib: ${PYTHON_EXEC} setup-lib.py install --flavor=git @echo @echo "Installation of lib finished." @@ -255,8 +255,8 @@ develop: src-lib/libopenzwave/libopenzwave.cpp @echo "Installation for developers of python-openzwave finished." tests: - #export NOSESKIP=False && ${NOSE_EXEC} $(NOSEOPTS) tests/ --with-progressive; unset NOSESKIP - export NOSESKIP=False && ${NOSE_EXEC} $(NOSEOPTS) tests/lib tests/api tests/manager ; unset NOSESKIP + export NOSESKIP=False && ${NOSE_EXEC} $(NOSEOPTS) tests/; unset NOSESKIP +#~ export NOSESKIP=False && ${NOSE_EXEC} $(NOSEOPTS) tests/lib tests/api tests/manager ; unset NOSESKIP @echo @echo "Tests for ZWave network finished." @@ -275,7 +275,7 @@ update: openzwave cd openzwave && git pull build: openzwave/.lib/ - ${PYTHON_EXEC} setup-lib.py build + ${PYTHON_EXEC} setup-lib.py build --flavor=dev src-lib/libopenzwave/libopenzwave.cpp: openzwave/.lib/ ${PYTHON_EXEC} setup-lib.py build --flavor=dev @@ -387,6 +387,8 @@ pypi_package:clean-archive cp -f pyozw_pkgconfig.py $(ARCHBASE)/python_openzwave/ cp -f pyozw_setup.py $(ARCHBASE)/python_openzwave/ cp -f pyozw_version.py $(ARCHBASE)/python_openzwave/ + cp -f pyozw_win.py $(ARCHBASE)/python_openzwave/ + cp -f pyozw_progressbar.py $(ARCHBASE)/python_openzwave/ cp -f python_openzwave.egg-info/PKG-INFO $(ARCHBASE)/python_openzwave/ -find $(ARCHBASE)/python_openzwave/ -name \*.pyc -delete 2>/dev/null || true -find $(ARCHBASE)/python_openzwave/ -name \*.so -delete 2>/dev/null || true @@ -417,7 +419,7 @@ commit: push @echo "Commits for branches master pushed on github." tag: - git tag v${python_openzwave_version} + -git tag v${python_openzwave_version} git push origin v${python_openzwave_version} @echo @echo "Tag pushed on github." @@ -461,9 +463,9 @@ new-version: validate-pr -$(MAKE) docs -git commit -m "Auto-commit for new-version" README.rst INSTALL_REPO.rst INSTALL_MAC.rst INSTALL_WIN.rst INSTALL_ARCH.rst LICENSE.txt COPYRIGHT.txt DEVEL.txt EXAMPLES.txt CHANGELOG.txt docs/ -git checkout $(ARCHIVES)/ - git commit -m "Update pyozw_version to ${python_openzwave_version}" pyozw_version.py + -git commit -m "Update pyozw_version to ${python_openzwave_version}" pyozw_version.py $(MAKE) debch - git commit -m "Update debian version to ${python_openzwave_version}" debian/ + -git commit -m "Update debian version to ${python_openzwave_version}" debian/ -$(MAKE) embed_openzave_master -$(MAKE) pypi_package -git add $(ARCHIVES)/python_openzwave-${python_openzwave_version}.zip && git commit -m "Add new pypi package" $(ARCHIVES)/python_openzwave-${python_openzwave_version}.zip && git push @@ -472,6 +474,7 @@ new-version: validate-pr -twine upload archives/python_openzwave-${python_openzwave_version}.zip -r pypitest -twine upload archives/python_openzwave-${python_openzwave_version}.zip -r pypi -$(MAKE) tag + sleep 60 $(MAKE) venv-pypitest-autobuild-tests $(MAKE) venv-pypilive-autobuild-tests @@ -496,16 +499,16 @@ venv-deps: common-deps apt-get install --force-yes -y python-all python-dev python3-all python3-dev python-virtualenv python-pip #~ apt-get install --force-yes -y python-wheel-common python3-wheel python-wheel python-pip-whl apt-get install --force-yes -y pkg-config wget unzip zip - pip install Cython + pip install Cython==0.28.6 pip install wheel docker-deps: common-deps apt-get install --force-yes -y python-all python-dev python3-all python3-dev python-virtualenv apt-get install --force-yes -y python3-pip python-pip python-wheel python3-wheel python-pip-whl - apt-get install --force-yes -y pkg-config wget unzip zip + apt-get install --force-yes -y wget unzip zip apt-get install --force-yes -y g++ libudev-dev libyaml-dev - pip install cython - pip3 install cython + pip install Cython==0.28.6 + pip3 install Cython==0.28.6 venv2: @echo //////////////////////////////////////////////////////////////////////////////////////////// @@ -515,8 +518,9 @@ venv2: @echo virtualenv --python=python2 venv2 + venv2/bin/python --version venv2/bin/pip install nose - venv2/bin/pip install Cython wheel six + venv2/bin/pip install Cython==0.28.6 wheel six pyserial venv2/bin/pip install 'Louie>=1.1' chmod 755 venv2/bin/activate -rm -f src-lib/libopenzwave/libopenzwave.cpp @@ -536,8 +540,9 @@ venv3: @echo virtualenv --python=python3 venv3 + venv3/bin/python --version venv3/bin/pip install nose - venv3/bin/pip install Cython wheel six + venv3/bin/pip install Cython==0.28.6 wheel six pyserial venv3/bin/pip install 'PyDispatcher>=2.0.5' chmod 755 venv3/bin/activate -rm -f src-lib/libopenzwave/libopenzwave.cpp @@ -550,14 +555,20 @@ venv3: @echo venv2-dev: venv2 src-lib/libopenzwave/libopenzwave.cpp - venv2/bin/python setup-lib.py install --flavor=dev - venv2/bin/python setup-api.py install - venv2/bin/python setup-manager.py install + venv2/bin/python setup-lib.py develop --flavor=dev + venv2/bin/python setup-api.py develop + venv2/bin/python setup-manager.py develop venv3-dev: venv3 src-lib/libopenzwave/libopenzwave.cpp - venv3/bin/python setup-lib.py install --flavor=dev - venv3/bin/python setup-api.py install -#~ venv3/bin/python setup-manager.py install + venv3/bin/python setup-lib.py develop --flavor=dev + venv3/bin/python setup-api.py develop + venv3/bin/python setup-manager.py develop + +venv2-install: venv2 src-lib/libopenzwave/libopenzwave.cpp + venv2/bin/python setup.py install --flavor=dev + +venv3-install: venv3 src-lib/libopenzwave/libopenzwave.cpp + venv3/bin/python setup.py install --flavor=dev venv2-shared: venv2 src-lib/libopenzwave/libopenzwave.cpp venv2/bin/python setup-lib.py install --flavor=shared @@ -575,23 +586,29 @@ venv-clean: -rm -rf venv3 -rm -f src-lib/libopenzwave/libopenzwave.cpp -venv-tests: venv2-dev venv3-dev +venv-tests: venv2-tests venv3-tests + +venv2-tests: venv2-dev @echo ========================================================================================== @echo + @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo - @echo "Launch tests for venv-autobuild-autobuild-tests." + @echo Tests for python2 @echo + @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo + -$(MAKE) PYTHON_EXEC=venv2/bin/python NOSE_EXEC=venv2/bin/nosetests tests + @echo - @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo - @echo Tests for python2 + @echo "Tests for venv2 done." @echo - @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo - -$(MAKE) PYTHON_EXEC=venv2/bin/python NOSE_EXEC=venv2/bin/nosetests tests + @echo ========================================================================================== + @echo +venv3-tests: venv3-dev @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo @@ -599,11 +616,12 @@ venv-tests: venv2-dev venv3-dev @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @echo + -$(MAKE) PYTHON_EXEC=venv3/bin/python NOSE_EXEC=venv3/bin/nosetests tests @echo @echo - @echo "Tests for venv-autobuild-autobuild-tests done." + @echo "Tests for venv3 done." @echo @echo @echo ========================================================================================== @@ -720,14 +738,14 @@ venv-pypitest-autobuild-tests: venv-clean venv2 venv3 -rm -f libopenzwave*.so venv2/bin/pip install "urwid>=1.1.1" - venv2/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave + venv2/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(embed-' venv2/bin/pip install "Cython" venv2/bin/pip uninstall python_openzwave -y - venv2/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" + venv2/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild - venv2/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" + venv2/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv2/bin/python venv2/bin/pyozw_check venv2/bin/python venv2/bin/pyozw_shell --help @@ -744,14 +762,14 @@ venv-pypitest-autobuild-tests: venv-clean venv2 venv3 -rm -f libopenzwave*.so venv3/bin/pip install "urwid>=1.1.1" - venv3/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave + venv3/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(embed-' venv3/bin/pip install "Cython" venv3/bin/pip uninstall python_openzwave -y - venv3/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" + venv3/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --install-option="--flavor=git" venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild - venv3/bin/pip install -i https://testpypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" + venv3/bin/pip install -i https://pypi.python.org/pypi -vvv python_openzwave --force --install-option="--flavor=git" venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild venv3/bin/python venv3/bin/pyozw_check venv3/bin/python venv3/bin/pyozw_shell --help @@ -790,16 +808,22 @@ venv-pypilive-autobuild-tests: venv-clean venv2/bin/pip install "urwid>=1.1.1" venv2/bin/pip install "nose" venv2/bin/pip install -vv python_openzwave + venv2/bin/python venv2/bin/pyozw_check -o raw venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(embed-' venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild -#~ venv2/bin/pip install Cython wheel - venv2/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" - venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv2/bin/pip install Cython==0.28.6 +#~ venv2/bin/pip install wheel venv2/bin/pip uninstall python_openzwave -y venv2/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv2/bin/python venv2/bin/pyozw_check -o raw venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(git-' venv2/bin/pip uninstall python_openzwave -y + venv2/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=ozwdev" + venv2/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv2/bin/python venv2/bin/pyozw_check -o raw + venv2/bin/python venv2/bin/pyozw_check -o raw|grep '(ozwdev-' + venv2/bin/pip uninstall python_openzwave -y @echo @echo //////////////////////////////////////////////////////////////////////////////////////////// @@ -817,16 +841,22 @@ venv-pypilive-autobuild-tests: venv-clean venv3/bin/pip install "nose" venv3/bin/pip install "urwid>=1.1.1" venv3/bin/pip install -vv python_openzwave + venv3/bin/python venv3/bin/pyozw_check -o raw venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(embed-' venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild -#~ venv3/bin/pip install Cython wheel - venv3/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" - venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv3/bin/pip install Cython==0.28.6 +#~ venv3/bin/pip install wheel venv3/bin/pip uninstall python_openzwave -y venv3/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=git" venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv3/bin/python venv3/bin/pyozw_check -o raw venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(git-' venv3/bin/pip uninstall python_openzwave -y + venv3/bin/pip install -vv python_openzwave --upgrade --install-option="--flavor=ozwdev" + venv3/bin/nosetests --verbose tests/lib/autobuild tests/api/autobuild tests/manager/autobuild + venv3/bin/python venv3/bin/pyozw_check -o raw + venv3/bin/python venv3/bin/pyozw_check -o raw|grep '(ozwdev-' + venv3/bin/pip uninstall python_openzwave -y -rm -f libopenzwave*.so @echo @@ -1297,7 +1327,7 @@ uninstallso: rm -Rf /usr/local/include/openzwave rm -Rf /usr/local/etc/openzwave rm -Rf /usr/local/share/doc/openzwave* - find /usr/local/lib/pkgconfig/ -iname libopenzwave.pc -delete + -find /usr/local/lib/pkgconfig/ -iname libopenzwave.pc -delete pyozw_pkgconfig.py: wget https://raw.githubusercontent.com/matze/pkgconfig/master/pkgconfig/pkgconfig.py diff --git a/README.rst b/README.rst index 4782c3a2..c4ae7c44 100755 --- a/README.rst +++ b/README.rst @@ -6,18 +6,18 @@ :target: https://circleci.com/gh/OpenZWave/python-openzwave :alt: Circle status -.. image:: https://img.shields.io/pypi/dm/python_openzwave.svg - :target: https://pypi.python.org/pypi/python_openzwave - :alt: Pypi downloads +.. image:: https://ci.appveyor.com/api/projects/status/2ogl8tx7o3pqphc9?svg=true + :target: https://ci.appveyor.com/project/bibi21000/python-openzwave + :alt: Appveyor status .. image:: https://img.shields.io/pypi/format/python_openzwave.svg :target: https://pypi.python.org/pypi/python_openzwave :alt: Pypi format -.. image:: https://img.shields.io/pypi/status/python_openzwave.svg - :target: https://pypi.python.org/pypi/python_openzwave - :alt: Pypi status - +.. image:: https://img.shields.io/badge/Documentation-ok-brightgreen.svg?style=flat + :target: http://openzwave.github.io/python-openzwave/index.html + :alt: Documentation + ================ python-openzwave ================ @@ -30,80 +30,79 @@ python-openzwave is a python wrapper for the openzwave c++ library : https://git * a full-event webapp example : flask + socket.io + jquery * a suite of tests * many examples - * `Full documentation `_ + * `Full documentation `_ -python-openzwave 0.4.0 is coming !!! -==================================== +python-openzwave 0.4.x is here !!! +================================== - - 0.4.0.x versions are for testers only. Don't use it in a production environement !!! +- New installation process via pip - - New installation process via pip - - - First, you need some build tools and libs. On ubuntu, you should use : +- First, you need some build tools and libs. On ubuntu, you should use : .. code-block:: bash sudo apt-get install --force-yes -y make libudev-dev g++ libyaml-dev - - Make your virtualenv and activate it : +- Make your virtualenv and activate it : .. code-block:: bash virtualenv --python=python3 venv3 source venv3/bin/activate - - Install the default (embed) flavor : +- Install the default flavor : .. code-block:: bash (venvX) pip install python_openzwave - - The previous command install python_openzwave statitically linked to sources downloaded from https://github.com/OpenZWave/python-openzwave/tree/master/archives. - You can change this using flavors. There is a bug in the package dependencies and flavors on some systems. You may need to install dependencies manualy : +- The previous command try to install python_openzwave with the flavor 'shared'. + If it can't find a precompiled library of openzwave, it will use the flavor 'embed' with sources downloaded from https://github.com/OpenZWave/python-openzwave/tree/master/archives. + You can change this using flavor option. + There is a bug in the package dependencies and flavors on some systems. You may need to install dependencies manualy : - - on python 2.7 : + - on python 2.7 : .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'Louie>=1.1' - - on python 3 : + - on python 3 : .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'PyDispatcher>=2.0.5' - - Choose your flavor : +- Choose your flavor : - embed : the default one. Download sources from https://github.com/OpenZWave/python-openzwave/tree/master/archives and build them. Python_openzwave is statically build using a cythonized version of libopenzwave. No need to install cython. - shared : if you have install openzwave as module manually, you can link python_openzwave to it. - git : download sources from openzwave github and link statically to it. - - embed_shared (experimental) : download sources from https://github.com/OpenZWave/python-openzwave/tree/master/archives, build and install as module on the system. + - embed_shared : download sources from https://github.com/OpenZWave/python-openzwave/tree/master/archives, build and install as module on the system. Python_openzwave use it. Need root access to install openzwave libs. - - git_shared (experimental) : download sources from openzwave github, build and install them as module on the system. + - git_shared : download sources from openzwave github, build and install them as module on the system. Python_openzwave use it. Need root access to install openzwave libs. - ozwdev and ozwdev_shared : use the dev branch of openzwave on github. - dev : for python_openzwave developers. Look for openzwave sources in a local folder specified by the LOCAL_OPENZWAVE environment variable (defaults to 'openzwave'). - - - Install it : +- Install it : .. code-block:: bash - (venvX) pip install python_openzwave --install-option="--flavor=git" + (venvX) pip install python_openzwave --no-deps --install-option="--flavor=git" - - You can update to the last version of openzwave using the git flavor : - +- You can update to the last version of openzwave using the git flavor : + .. code-block:: bash (venvX) pip uninstall -y python_openzwave - (venvX) pip install python_openzwave --no-cache-dir --install-option="--flavor=git" + (venvX) pip install python_openzwave --no-cache-dir --no-deps --install-option="--flavor=git" - - At last, you can launch pyozw_check: +- At last, you can launch pyozw_check to test your installation : If no usb stick is connected to the machine, launch : @@ -164,6 +163,50 @@ python-openzwave 0.4.0 is coming !!! Try to destroy manager Try to destroy options + You can list the nodes on your network using : + + .. code-block:: bash + + (venvX) pyozw_check -l -d /dev/ttyUSB0 -t 60 + + .. code-block:: bash + + ------------------------------------------------------------------------------- + Define options for device /dev/ttyUSB0 + Start network + Wait for network (30s) + Network is ready + ------------------------------------------------------------------------------- + Controller capabilities : {'primaryController', 'staticUpdateController'} + Controller node capabilities : {'listening', 'primaryController', 'staticUpdateController', 'beaming'} + Nodes in network : 4 + Driver statistics : {'noack': 6, 'routedbusy': 0, 'readCnt': 115, 'ACKWaiting': 0, 'badChecksum': 0, 'broadcastReadCnt': 0, 'NAKCnt': 0, 'broadcastWriteCnt': 9, 'dropped': 0, 'CANCnt': 0, 'callbacks': 0, 'OOFCnt': 0, 'readAborts': 0, 'badroutes': 0, 'SOFCnt': 115, 'netbusy': 0, 'writeCnt': 49, 'nondelivery': 0, 'ACKCnt': 49, 'retries': 0} + ------------------------------------------------------------ + 1 - Name : ( Location : ) + 1 - Ready : True / Awake : True / Failed : False + 1 - Manufacturer : Aeotec ( id : 0x0086 ) + 1 - Product : DSA02203 Z-Stick S2 ( id : 0x0001 / type : 0x0002 ) + 1 - Version : 3 / Secured : False / Zwave+ : False + 1 - Command classes : {'COMMAND_CLASS_NO_OPERATION', 'COMMAND_CLASS_BASIC'} + 1 - Capabilities : {'staticUpdateController', 'listening', 'primaryController', 'beaming'} + 1 - Neigbors : {4} / Power level : None + 1 - Is sleeping : False / Can wake-up : False / Battery level : None + + ... + + ------------------------------------------------------------ + 4 - Name : ( Location : ) + 4 - Ready : True / Awake : True / Failed : False + 4 - Manufacturer : GreenWave ( id : 0x0099 ) + 4 - Product : PowerNode 6 port ( id : 0x0004 / type : 0x0003 ) + 4 - Version : 4 / Secured : False / Zwave+ : False + 4 - Command classes : {'COMMAND_CLASS_BASIC', 'COMMAND_CLASS_CONFIGURATION', 'COMMAND_CLASS_SWITCH_BINARY', 'COMMAND_CLASS_VERSION', 'COMMAND_CLASS_CRC_16_ENCAP', 'COMMAND_CLASS_MANUFACTURER_SPECIFIC', 'COMMAND_CLASS_ASSOCIATION', 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 'COMMAND_CLASS_METER', 'COMMAND_CLASS_PROTECTION', 'COMMAND_CLASS_NO_OPERATION', 'COMMAND_CLASS_SWITCH_ALL'} + 4 - Capabilities : {'listening', 'routing', 'beaming'} + 4 - Neigbors : {1} / Power level : None + 4 - Is sleeping : False / Can wake-up : False / Battery level : None + + ... + - The old manager is now available via the pyozw_shell command. You need to install module "urwid>=1.1.1" with pip before using it. @@ -197,15 +240,6 @@ python-openzwave 0.4.0 is coming !!! - Please report your successful installations here : https://github.com/OpenZWave/python-openzwave/issues/73 -python-openzwave 0.3.0 is out !!! -================================= - -Look at CHANGELOG to see new features and release notes. - -Look at INSTALL_REPO to test it now. - -Look at INSTALL_ARCH to install from archive : no need to install cython anymore. - Support ======= You can ask for support on the google group : http://groups.google.com/d/forum/python-openzwave-discuss. @@ -216,87 +250,3 @@ Pull requests ============= Please read DEVEL documentation before submitting pull request. A lot of project tasks are done automatically or with makefile, so they must be done in a certain place or in a special order. - -Migrating from python-openzwave 0.2.X to 0.3.0 -============================================== -I need to update source tree of python-openzwave and modules's names because of a bug in setuptools -: https://bitbucket.org/pypa/setuptools/issue/230/develop-mode-does-not-respect-src . -Sorry for that. - -Update your sources: - -.. code-block:: bash - - git pull - -Before building python-openzwave 0.3.0, you must uninstall the old version : - -.. code-block:: bash - - sudo make uninstall - -About cython : I've made many tests using cython installed via pip : (0.20, 0.21 and 0.22). -Compilation is ok but a segfault appears when launching the tests. Please remove it. - -.. code-block:: bash - - sudo pip uninstall Cython - -You also need to make some minor updates in you code, look at CHANGELOG - -If you have problems, please submit an issue with : - - - cython -V - - the content of the directory /usr/local/lib/python2.7/dist-packages/ (for python2.7) - - the content of /usr/local/lib/python2.7/dist-packages/easy-install.pth (for python 2.7) - - -Ubuntu 64bits ... and the others -================================ - -If you're using Ubuntu 64 bits (and mayde others) and keep your distribution up to date, -you certainly have the segfault problem. - -Ubuntu 12.04 and 14.04 seems to be affected by this bug. Ubuntu 15.10 and Debian Jessie not. - -It appears with the last update of python : - -.. code-block:: bash - - $ python - Python 2.7.6 (default, Jun 22 2015, 17:58:13) - [GCC 4.8.2] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - - -I've open a discussion on cython-users here : https://groups.google.com/forum/#!topic/cython-users/mRsviGuCFOk - -The only way I found to avoid this is to rebuild and reinstall the old release of python : - -.. code-block:: bash - - wget https://launchpad.net/ubuntu/+archive/primary/+files/python2.7_2.7.6-8.dsc https://launchpad.net/ubuntu/+archive/primary/+files/python2.7_2.7.6.orig.tar.gz https://launchpad.net/ubuntu/+archive/primary/+files/python2.7_2.7.6-8.diff.gz - - dpkg-source -x python2.7_2.7.6-8.dsc - - sudo apt-get build-dep python2.7 - - cd python2.7-2.7.6 - - dpkg-buildpackage - -Wait, wait and await again :) - -.. code-block:: bash - - cd .. - - sudo dpkg -i *.deb - -To prevent future updates of python, you could mark its packages. For example, if you use apt to update your distribution, use the following command : - -.. code-block:: bash - - sudo apt-mark hold idle-python2.7 libpython2.7-minimal python2.7-dbg python2.7-minimal libpython2.7 libpython2.7-stdlib python2.7-dev libpython2.7-dbg libpython2.7-testsuite python2.7-doc libpython2.7-dev python2.7 python2.7-examples - -Some users have reported that building python-openzwave using the archive (INSTALL_ARCH) can also do the trick. Let me know if it works for you. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..0dfab890 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,140 @@ +environment: + PYPI_USER: + secure: yna6KiH2GE3Ka1G5a3TlUQ== + PYPI_PASSWORD: + secure: UpISOsYyHdCzurReV6FcTA== + + global: + # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the + # /E:ON and /V:ON options are not enabled in the batch script intepreter + # See: http://stackoverflow.com/a/13751649/163740 + CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd" + + matrix: + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6.x" + PYTHON_ARCH: "32" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python36-x64" + PYTHON_VERSION: "3.6.x" + PYTHON_ARCH: "64" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7.x" + PYTHON_ARCH: "32" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python27-x64" + PYTHON_VERSION: "2.7.x" + PYTHON_ARCH: "64" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python34" + PYTHON_VERSION: "3.4.x" + PYTHON_ARCH: "32" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python34-x64" + PYTHON_VERSION: "3.4.x" + PYTHON_ARCH: "64" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python37" + PYTHON_VERSION: "3.7.x" + PYTHON_ARCH: "32" + + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PYTHON: "C:\\Python37-x64" + PYTHON_VERSION: "3.7.x" + PYTHON_ARCH: "64" + +deploy: + - provider: Environment + name: production + on: + APPVEYOR_REPO_TAG: true + +install: + # If there is a newer build queued for the same PR, cancel this one. + # The AppVeyor 'rollout builds' option is supposed to serve the same + # purpose but it is problematic because it tends to cancel builds pushed + # directly to master instead of just PR builds (or the converse). + # credits: JuliaLang developers. + - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod ` + https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | ` + Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { ` + throw "There are newer queued builds for this pull request, failing early." } + - ECHO "Filesystem root:" + - ps: "ls \"C:/\"" + + #~ - ECHO "Installed SDKs:" + #~ - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\"" + + - ECHO "Installed prgrams:" + - ps: "ls \"C:/Program Files/\"" + - ps: "ls \"C:/Program Files (x86)/\"" + - ps: "ls \"C:/Program Files (x86)/MSBuild/\"" + - ps: "ls \"C:/Program Files (x86)/Windows Kits/\"" + + # Prepend newly installed Python to the PATH of this build (this cannot be + # done from inside the powershell script as it would require to restart + # the parent CMD process). + - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" + + # Check that we have the expected version and architecture for Python + - "python --version" + - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" + + # Upgrade to the latest version of pip to avoid it displaying warnings + # about it being out of date. + - "python -m pip install --disable-pip-version-check --user --upgrade pip" + + # Install the build dependencies of the project. If some dependencies contain + # compiled extensions and are not provided as pre-built wheel packages, + # pip will build them from source using the MSVC compiler matching the + # target Python version and architecture + # - "%CMD_IN_ENV% pip install Cython six" + - "python -m pip install wheel" + - "python -m pip install pyserial" + - "python -m pip install Cython six" + - "python -m pip install nose" + - "python -m pip install twine" + + - ps: Write-Host "PYTHON_VERSION $env:PYTHON_VERSION" + + - cmd: IF "%PYTHON_VERSION%" == "2.7.x" ( python -m pip install Louie ) ELSE ( python -m pip install PyDispatcher ) + + - git clone git://github.com/OpenZWave/open-zwave.git C:\projects\python-openzwave\openzwave + +build_script: + # Build the compiled extension + # "python pyozw_win.py" + - "python setup.py install --flavor=dev" + +test_script: + # Run the project tests + - "pyozw_check" + - "nosetests --verbose tests/lib/autobuild tests/api/autobuild" + +after_test: + # If tests are successful, create binary packages for the project. + - python setup.py bdist_wheel --flavor=dev + #~ - "python setup.py bdist_wininst" + #~ - "%CMD_IN_ENV% python setup.py bdist_msi" + - ps: "ls dist" + +artifacts: + # Archive the generated packages in the ci.appveyor.com build report. + - path: dist/* + name: windowswheels + +deploy_script: + # upload to pypi for Windows + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (echo "Uploading wheels") + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (set HOME=%USERPROFILE%) + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (twine upload dist/*.whl --repository-url https://upload.pypi.org/legacy/ -u %PYPI_USER% -p %PYPI_PASSWORD%) + - cmd: IF "%APPVEYOR_REPO_TAG%" == "true" (echo "Finished Artifact Deployment" ) diff --git a/archives/open-zwave-master-0.4.1.zip b/archives/open-zwave-master-0.4.1.zip new file mode 100644 index 00000000..676c2903 Binary files /dev/null and b/archives/open-zwave-master-0.4.1.zip differ diff --git a/archives/open-zwave-master-0.4.10.zip b/archives/open-zwave-master-0.4.10.zip new file mode 100644 index 00000000..9b9898ad Binary files /dev/null and b/archives/open-zwave-master-0.4.10.zip differ diff --git a/archives/open-zwave-master-0.4.11.zip b/archives/open-zwave-master-0.4.11.zip new file mode 100644 index 00000000..2247bde9 Binary files /dev/null and b/archives/open-zwave-master-0.4.11.zip differ diff --git a/archives/open-zwave-master-0.4.14.zip b/archives/open-zwave-master-0.4.14.zip new file mode 100644 index 00000000..b84d0d8b Binary files /dev/null and b/archives/open-zwave-master-0.4.14.zip differ diff --git a/archives/open-zwave-master-0.4.15.zip b/archives/open-zwave-master-0.4.15.zip new file mode 100644 index 00000000..12e55244 Binary files /dev/null and b/archives/open-zwave-master-0.4.15.zip differ diff --git a/archives/open-zwave-master-0.4.16.zip b/archives/open-zwave-master-0.4.16.zip new file mode 100644 index 00000000..670b7f68 Binary files /dev/null and b/archives/open-zwave-master-0.4.16.zip differ diff --git a/archives/open-zwave-master-0.4.17.zip b/archives/open-zwave-master-0.4.17.zip new file mode 100644 index 00000000..ffa36699 Binary files /dev/null and b/archives/open-zwave-master-0.4.17.zip differ diff --git a/archives/open-zwave-master-0.4.18.zip b/archives/open-zwave-master-0.4.18.zip new file mode 100644 index 00000000..9897a92f Binary files /dev/null and b/archives/open-zwave-master-0.4.18.zip differ diff --git a/archives/open-zwave-master-0.4.19.zip b/archives/open-zwave-master-0.4.19.zip new file mode 100644 index 00000000..62b61c1d Binary files /dev/null and b/archives/open-zwave-master-0.4.19.zip differ diff --git a/archives/open-zwave-master-0.4.2.zip b/archives/open-zwave-master-0.4.2.zip new file mode 100644 index 00000000..14c251aa Binary files /dev/null and b/archives/open-zwave-master-0.4.2.zip differ diff --git a/archives/open-zwave-master-0.4.3.zip b/archives/open-zwave-master-0.4.3.zip new file mode 100644 index 00000000..9e3568d8 Binary files /dev/null and b/archives/open-zwave-master-0.4.3.zip differ diff --git a/archives/open-zwave-master-0.4.4.zip b/archives/open-zwave-master-0.4.4.zip new file mode 100644 index 00000000..826ac8e3 Binary files /dev/null and b/archives/open-zwave-master-0.4.4.zip differ diff --git a/archives/open-zwave-master-0.4.5.zip b/archives/open-zwave-master-0.4.5.zip new file mode 100644 index 00000000..c9a94777 Binary files /dev/null and b/archives/open-zwave-master-0.4.5.zip differ diff --git a/archives/open-zwave-master-0.4.6.zip b/archives/open-zwave-master-0.4.6.zip new file mode 100644 index 00000000..c26caf17 Binary files /dev/null and b/archives/open-zwave-master-0.4.6.zip differ diff --git a/archives/open-zwave-master-0.4.7.zip b/archives/open-zwave-master-0.4.7.zip new file mode 100644 index 00000000..10e0a163 Binary files /dev/null and b/archives/open-zwave-master-0.4.7.zip differ diff --git a/archives/open-zwave-master-0.4.8.zip b/archives/open-zwave-master-0.4.8.zip new file mode 100644 index 00000000..f5d3cb1e Binary files /dev/null and b/archives/open-zwave-master-0.4.8.zip differ diff --git a/archives/open-zwave-master-0.4.9.zip b/archives/open-zwave-master-0.4.9.zip new file mode 100644 index 00000000..f8899041 Binary files /dev/null and b/archives/open-zwave-master-0.4.9.zip differ diff --git a/archives/python_openzwave-0.4.1.zip b/archives/python_openzwave-0.4.1.zip new file mode 100644 index 00000000..a2925d22 Binary files /dev/null and b/archives/python_openzwave-0.4.1.zip differ diff --git a/archives/python_openzwave-0.4.10.zip b/archives/python_openzwave-0.4.10.zip new file mode 100644 index 00000000..7762b7ff Binary files /dev/null and b/archives/python_openzwave-0.4.10.zip differ diff --git a/archives/python_openzwave-0.4.11.zip b/archives/python_openzwave-0.4.11.zip new file mode 100644 index 00000000..9ab4b224 Binary files /dev/null and b/archives/python_openzwave-0.4.11.zip differ diff --git a/archives/python_openzwave-0.4.14.zip b/archives/python_openzwave-0.4.14.zip new file mode 100644 index 00000000..31798f3d Binary files /dev/null and b/archives/python_openzwave-0.4.14.zip differ diff --git a/archives/python_openzwave-0.4.15.zip b/archives/python_openzwave-0.4.15.zip new file mode 100644 index 00000000..d341a2e2 Binary files /dev/null and b/archives/python_openzwave-0.4.15.zip differ diff --git a/archives/python_openzwave-0.4.16.zip b/archives/python_openzwave-0.4.16.zip new file mode 100644 index 00000000..c08369f2 Binary files /dev/null and b/archives/python_openzwave-0.4.16.zip differ diff --git a/archives/python_openzwave-0.4.17.zip b/archives/python_openzwave-0.4.17.zip new file mode 100644 index 00000000..f1008c65 Binary files /dev/null and b/archives/python_openzwave-0.4.17.zip differ diff --git a/archives/python_openzwave-0.4.18.zip b/archives/python_openzwave-0.4.18.zip new file mode 100644 index 00000000..4dafdcfd Binary files /dev/null and b/archives/python_openzwave-0.4.18.zip differ diff --git a/archives/python_openzwave-0.4.19.zip b/archives/python_openzwave-0.4.19.zip new file mode 100644 index 00000000..0c9cafef Binary files /dev/null and b/archives/python_openzwave-0.4.19.zip differ diff --git a/archives/python_openzwave-0.4.2.zip b/archives/python_openzwave-0.4.2.zip new file mode 100644 index 00000000..f79ae946 Binary files /dev/null and b/archives/python_openzwave-0.4.2.zip differ diff --git a/archives/python_openzwave-0.4.3.zip b/archives/python_openzwave-0.4.3.zip new file mode 100644 index 00000000..dc37d2e6 Binary files /dev/null and b/archives/python_openzwave-0.4.3.zip differ diff --git a/archives/python_openzwave-0.4.4.zip b/archives/python_openzwave-0.4.4.zip new file mode 100644 index 00000000..ec98edc5 Binary files /dev/null and b/archives/python_openzwave-0.4.4.zip differ diff --git a/archives/python_openzwave-0.4.5.zip b/archives/python_openzwave-0.4.5.zip new file mode 100644 index 00000000..db6317d6 Binary files /dev/null and b/archives/python_openzwave-0.4.5.zip differ diff --git a/archives/python_openzwave-0.4.6.zip b/archives/python_openzwave-0.4.6.zip new file mode 100644 index 00000000..9c6fa0f8 Binary files /dev/null and b/archives/python_openzwave-0.4.6.zip differ diff --git a/archives/python_openzwave-0.4.7.zip b/archives/python_openzwave-0.4.7.zip new file mode 100644 index 00000000..e0c43de7 Binary files /dev/null and b/archives/python_openzwave-0.4.7.zip differ diff --git a/archives/python_openzwave-0.4.8.zip b/archives/python_openzwave-0.4.8.zip new file mode 100644 index 00000000..26d47a4c Binary files /dev/null and b/archives/python_openzwave-0.4.8.zip differ diff --git a/archives/python_openzwave-0.4.9.zip b/archives/python_openzwave-0.4.9.zip new file mode 100644 index 00000000..51918e6a Binary files /dev/null and b/archives/python_openzwave-0.4.9.zip differ diff --git a/debian/changelog b/debian/changelog index 688a3366..8744ed4c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -python-openzwave (0.4.0.35) UNRELEASED; urgency=medium +python-openzwave (0.4.19) UNRELEASED; urgency=medium * Try to fix * Automatic release from upstream. Look at CHANGELOG.txt @@ -9,8 +9,27 @@ python-openzwave (0.4.0.35) UNRELEASED; urgency=medium * Automatic release from upstream. Look at CHANGELOG.txt * Automatic release from upstream. Look at CHANGELOG.txt * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt + * Automatic release from upstream. Look at CHANGELOG.txt - -- bibi21000 Tue, 06 Jun 2017 15:30:30 +0200 + -- bibi21000 Wed, 20 Mar 2019 10:57:44 +0100 python-openzwave (0.3.0b8) UNRELEASED; urgency=medium diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 9fc2bc25..ec9d1b02 100755 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -4,6 +4,75 @@ Changelog ========= +python_openzwave 0.4.18.x: + * Fix python 2.7/appveyor + * Add serial port auto-detection + + +python_openzwave 0.4.17.x: + * Add wheels for Windows + + +python_openzwave 0.4.16.x: + * Fix appveyor build for windows + + +python_openzwave 0.4.15.x: + * Update embeded package + + +python_openzwave 0.4.14.x: + * Use Cython 0.28.6 + * Update embeded package + + +python_openzwave 0.4.12.x: + * Improve support Windows + * COMMAND_CLASS_ZWAVE_PLUS_INFO renamed to COMMAND_CLASS_ZWAVEPLUS_INFO + * Update thermostat + * Update embeded package + + +python_openzwave 0.4.11.x: + * Update embeded package + + +python_openzwave 0.4.10.x: + * Improve support Windows in pip + * Improve tests Windows + * Update contructors for scenes and groups + + +python_openzwave 0.4.9.x: + * Improve support Windows in pip + * Update tests + + +python_openzwave 0.4.6.x: + * First try to support Windows in pip + + +python_openzwave 0.4.5.x: + * Fix bug in node statistics and add test. + * Update Makefile to build flavor dev + * Update pyozw_check. + * Update default flavor : check cython is here before choosing shared + * Fix controller.update_ozw_config when directory isn't writable + + +python_openzwave 0.4.4.x: + * Add new options to pyozw_check to list nodes on network. + + +python_openzwave 0.4.3.x: + * Fix bug in default flavor. + + +python_openzwave 0.4.1.x: + * Update the default flavor : try to use a precompiled library. If can't find one, use the embeded package. + * Add method to controller to get new config from github. + + python_openzwave 0.4.0.x: * New installation process via pip diff --git a/docs/DEVEL.rst b/docs/DEVEL.rst index 7ab0a978..1e6a79f6 100644 --- a/docs/DEVEL.rst +++ b/docs/DEVEL.rst @@ -4,14 +4,17 @@ Developers information ====================== + How to develop for python-openzwave =================================== -Get the sources +Fork the project on Github. + +Get the sources : .. code-block:: bash - git clone https://github.com/OpenZWave/python-openzwave + git clone https://github.com/yourname/python-openzwave You can install all the dependances to develop for python-openzwave using the command : @@ -19,74 +22,36 @@ You can install all the dependances to develop for python-openzwave using the co sudo make developer-deps -You must now install python-openzwave in develop mode - -.. code-block:: bash - - make develop - -Your password will be asked (by sudo) for installing eggs in your local directory. - -Develop, test, debug, test, ... :) - -Update the documentation if needed. You surely found the documentation useful, so please keep it up to date. - -You can create an account on travis or docker to run the tests. - -At last but not least, submit your request. - -How to develop for libopenzwave (was python-openzwave-lib) -========================================================== -After updating the pyx, you need to reinstall it. Otherwise, your changes will not be applied : +You must now install python-openzwave in develop mode. Depending on which python version you prefer, use : .. code-block:: bash - make develop - -Tests -===== - -First, install the dependances : + make venv2-dev +or + .. code-block:: bash - sudo make tests-deps + make venv2-dev -To launch all the tests suite (about 140 tests), use the following command : +Keep in mind that your updates must be python 2 / python 3 compatible. -.. code-block:: bash - - make tests - -To launch particular tests : +Develop, test, debug, test, ... :) -.. code-block:: bash +Update the documentation if needed. You surely found the documentation useful, so please keep it up to date. - nosetests --verbosity=2 tests/api/test_controller_command.py +It a good idea to add automatic tests. -Some tests need manual operations (ie to add a node, to remove one, ...). For example, to test the remove node, use : +Launch the full test suite (for python 2 and python 3) : .. code-block:: bash - export MANUALSKIP='False' && nosetests --verbosity=2 tests/api/test_controller_command.py -m test_150 && unset MANUALSKIP - test_150_command_remove_node_and_wait_for_user (tests.api.test_controller_command.TestControllerCommand) ... ok - - ---------------------------------------------------------------------- - Ran 1 test in 16.031s - - OK + make venv-tests -You should push the inclusion button of the node before the end of the test. +At last but not least, submit your request with the result of tests in the comment. -Some tests don't need a ZWave Stick to be launched, so they can be run on the autobuilders (travis, docker, ...). Place them in the autobuild directory. +If you don't follow the previous steps, your PR will be refused or letting in pending state until I've got time to test it. -Travis-ci, Docker Hub, nosetests and pylint are used to test quality of code. There reports are here : - - - Docker : https://registry.hub.docker.com/u/bibi21000/python-openzwave/ - - Travis : https://travis-ci.org/bibi21000/python-openzwave - - `Nosetests report `_ - - `Coverage report `_ - - `Pylint report `_ Documentation ============= @@ -98,90 +63,6 @@ First, install the dependances : sudo make doc-deps Documentation is managed with sphinx. -Don't utpdate txt files (README, INSTALL, ...), update the RST sources in docs. -Use the following commands to generate all docs files (txt, html and joomla) - -You need to have installed python-openzwave (in either develop or install mode) before generating the documentation. - -.. code-block:: bash - - make docs - -Static vs dynamic (or shared) -============================= -The openzwave (c++) lib needs to run as a singleton : it means that it MUST have only one instance of the manager running on your computer. - -There is 2 ways of linking libraries with a program : - - * static : includes a copy of the library in your binary program. - This means that your program has its own instance of the library. - This the way the install.sh runs. - So you CAN'T have another program (like the control-panel) running when using the python-openzwave library - - * dynamic or shared : includes a link to the library in your binary program. - This means that your program share the library with other programs. - In this case, the instance is owned directly by the library. - This the way the debian package works. So you CAN have another program running when using the python-openzwave library. - Of course, this program MUST use the shared library too. - -About sudo -========== -If you are like me and don't like root (and sudo), you can use the following tip to install packages via pip : - -Look at your python local library, it should looks like : - -.. code-block:: bash - - ls -lisa /usr/local/lib/python2.7/dist-packages/ - total 2428 - 1445174 12 drwxrwsr-x 115 root staff 12288 avril 9 21:35 . - 1445172 4 drwxrwsr-x 4 root staff 4096 mai 2 2014 .. - 1457164 4 drwxr-sr-x 5 root staff 4096 nov. 26 2013 actdiag - 1715480 4 drwxr-sr-x 2 root staff 4096 nov. 26 2013 actdiag-0.5.1.egg-info - 1457163 4 -rw-r--r-- 1 root staff 1004 nov. 26 2013 actdiag_sphinxhelper.py - 1457172 4 -rw-r--r-- 1 root staff 620 nov. 26 2013 actdiag_sphinxhelper.pyc - .... - -So, add your common user to the staff group : - -.. code-block:: bash - - sudo usermod -a -G staff userName - -Add the write right to the group staff - -.. code-block:: bash - - sudo chmod -Rf g+w /usr/local/lib/python2.7/dist-packages/ - -And now, it's time log off and log on. Groups are checked when you open the session. - -You can now install your packages without sudo. - -Python3 and virtualenv -====================== -Python 3 is actually not supported. - -A branch (python3) has been created with a special Dockerfile. It build python-openzwave and launch some tests. -This branch is automatically merged from master at "make commit". - -So please, do not directly push under python3 branch. Make your developments under master or another branch. - -It's important for me have python2/python3 compatibilty in the master branch. -cython can help for this : http://docs.cython.org/src/tutorial/strings.html - -The Makefile sill try to automatically configure your version of python (running python --version). - -If you want to install python-openzwave in a python virtual environnement, you should use something like : - -.. code-block:: bash - - make VIRTUAL_ENV=/path/to/my/venv ... - -If you use python 3 and your python executable is called python3 : - -.. code-block:: bash - make PYTHON_EXEC=python3 ... +Don't update txt and rst files (README, INSTALL, ...) in the root directory, update the RST sources in docs. -You can also put these variables in a CONFIG.make file instead of passing them to the command line diff --git a/docs/INSTALL.rst b/docs/INSTALL.rst new file mode 100755 index 00000000..890e529c --- /dev/null +++ b/docs/INSTALL.rst @@ -0,0 +1,41 @@ +:orphan: + +==================================== +Installing python-openzwave from pip +==================================== + + +Flavors +======= + +Flavor embed +------------ + + +Flavor shared +------------- + + +Flavor git +---------- + + +Flavor ozwdev +------------- + + +Flavor ozwdev +------------- + + +Flavor dev +---------- + + +OS +== + +Windows +------- + + diff --git a/docs/INSTALL_WIN.rst b/docs/INSTALL_WIN.rst index 8c102ef1..6ced83fc 100755 --- a/docs/INSTALL_WIN.rst +++ b/docs/INSTALL_WIN.rst @@ -5,51 +5,183 @@ Installing python-openzwave on Windows ====================================== -This HOW-TO is for 0.4.X. +Install Microsoft tools +======================= -It should be possible to make it pip friendly. Need a command line to build openzwave c++ lib. +This package use MSBuild.exe to build openzwave code. -How To Build python-openzwave on Windows with VS2015 -==================================================== +You can find it in Visual Studio 2017 or Visual Studio 2015. -Assuming Python 3.5 is set in PATH -Assuming your python environment has pip, cython, setuptools +It's also possible to get it as a separate package. +Only release 14.0 and 15.0 of Microsft Build Tools are tested. -Get sources ------------ +You nust use the C++ compiler used to build your version of python : https://wiki.python.org/moin/WindowsCompilers -.. code-block:: bash - git clone https://github.com/openzwave/python-openzwave.git +Install other tools +=================== - cd python-openzwave - git clone git://github.com/OpenZWave/open-zwave.git openzwave +You need git to clone the repository and python (32 bits or 64 bits). Add it to your PATH. + +Install dependencies : + + - for python 2.7 : - cd openzwave - git checkout Dev - cd .. - git checkout + .. code-block:: bash + (venvX) pip install Cython six Louie -Build open-zwave ----------------- + - for python 3 : -Open openzwave/cpp/build/windows/vs2010/OpenZWave.sln in Visual Studio + .. code-block:: bash -When asked, accept the project upgrade to VS2015 + (venvX) pip install Cython six PyDispatcher -Build Win32|Release +clone repositories +================== +Clone python-openzwave: + + +.. code-block:: bash -Build python_openzwave ----------------------- + git clone https://github.com/OpenZWave/python-openzwave.git -From a Command Prompt, install it : +And clone open-zwave inside python-openzwave : .. code-block:: bash - python setup install --dev + cd python-openzwave + git clone https://github.com/OpenZWave/open-zwave.git openzwave + +It's mandatory to clone the previous repository in a directory called openzwave (not open-zwave) + +Visual studio +============= + +Copy vs2010 in a new directory vs2017 (or vs2015 depending of which Visual Studio you use) : + +.. code-block:: bash -Reference for 0.3.X : https://github.com/OpenZWave/python-openzwave/issues/53 + xcopy openzwave\cpp\build\windows\vs2010 openzwave\cpp\build\windows\vs2017 /s /e /h + +Open the project (openzwave\cpp\build\windows\vs2017\OpenZWave.sln) in your Visual Studio. +If you want to build for 64bits, add a new target for it. And finally close it. + +Python-openzwave +================ + +Build and install python-openzwave : + + .. code-block:: bash + + python setup.py install --flavor=dev + + .. code-block:: bash + + sysargv ['setup.py', 'install'] + thon setup.py install --flavor=dev + Requirement already satisfied: Cython in c:\program files (x86)\python36-32\lib\site-packages + {'name': 'libopenzwave', 'sources': ['src-lib/libopenzwave/libopenzwave.pyx'], 'include_dirs': ['openzwave/cpp/src', 'openzwave + /cpp/src/value_classes', 'openzwave/cpp/src/platform', 'openzwave/cpp/build/windows', 'src-lib/libopenzwave', 'openzwave/cpp/bu + ild/windows/vs2017/Release/'], 'define_macros': [('PY_LIB_VERSION', '0.4.4'), ('PY_SSIZE_T_CLEAN', 1), ('PY_LIB_FLAVOR', 'dev') + , ('PY_LIB_BACKEND', 'cython')], 'libraries': ['setupapi', 'msvcrt', 'ws2_32', 'dnsapi'], 'extra_objects': ['openzwave/cpp/buil + d/windows/vs2017/Release//OpenZWave.lib'], 'extra_compile_args': [], 'extra_link_args': [], 'language': 'c++'} + ['six', 'PyDispatcher>=2.0.5', 'Cython'] + Requirement already satisfied: Cython in c:\program files (x86)\python36-32\lib\site-packages + running install + flavor --flavor=dev c:\program files (x86)\python36-32\lib\site-packages + running build_openzwave + Found MSBuild.exe : c:/Program Files (x86)/Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe + Found arch : Win32 wave + Found Visual Studio project : vs2017 (x86)/Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe + Found build path : openzwave/cpp/build/windows/vs2017/Release/ + ... + ... + byte-compiling C:\Program Files (x86)\Python36-32\Lib\site-packages\python_openzwave\scripts\__init__.py to __init__.cpython-36 + .pyc + running install_egg_info + running egg_info + writing python_openzwave.egg-info\PKG-INFO + writing dependency_links to python_openzwave.egg-info\dependency_links.txt + writing entry points to python_openzwave.egg-info\entry_points.txt + ================================================================ + .\scripts\allusers.bat + this script is executed for all users + delete/rename it if you dont need it + ================================================================ + Page de codes active�: 437 + +And finally, test it : + + .. code-block:: bash + + pyozw_check -l -d COM2 -t 30 + + .. code-block:: bash + + ------------------------------------------------------------------------------- + Define options for device COM2 + Start network + Wait for network awake (30s) + ------------------------------------------------------------------------------- + Network is awaked. Talk to controller. + Get python_openzwave version : 0.4.4 + Get python_openzwave config version : Original Z-Wave 2.78 + Get python_openzwave flavor : dev + Get openzwave version : 1.4.2942 + Get config path : C:\Program Files\Python36\lib\site-packages\python_openzwave\ozw_config + Controller capabilities : {'primaryController', 'staticUpdateController'} + Controller node capabilities : {'listening', 'primaryController', 'beaming', 'staticUpdateController'} + Nodes in network : 4 + ------------------------------------------------------------------------------- + Wait for network ready (30s) + ------------------------------------------------------------------------------- + Network is ready. Get nodes + ------------------------------------------------------------ + 1 - Name : ( Location : ) + 1 - Ready : True / Awake : True / Failed : False + 1 - Manufacturer : Aeotec ( id : 0x0086 ) + 1 - Product : DSA02203 Z-Stick S2 ( id : 0x0001 / type : 0x0002 / Version : 3) + 1 - Command classes : set() + 1 - Capabilities : {'listening', 'primaryController', 'beaming', 'staticUpdateController'} + 1 - Neighbors : {4} / Power level : None + 1 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 2 - Name : ( Location : ) + 2 - Ready : True / Awake : True / Failed : False + 2 - Manufacturer : ( id : 0x0000 ) + 2 - Product : ( id : 0x0000 / type : 0x0000 / Version : 2) + 2 - Command classes : set() + 2 - Capabilities : {'listening', 'routing'} + 2 - Neighbors : {3} / Power level : None + 2 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 3 - Name : ( Location : ) + 3 - Ready : False / Awake : True / Failed : True + 3 - Manufacturer : ( id : 0x0000 ) + 3 - Product : ( id : 0x0000 / type : 0x0000 / Version : 3) + 3 - Command classes : set() + 3 - Capabilities : {'listening', 'routing', 'beaming'} + 3 - Neighbors : set() / Power level : None + 3 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + 4 - Name : ( Location : ) + 4 - Ready : True / Awake : True / Failed : False + 4 - Manufacturer : GreenWave ( id : 0x0099 ) + 4 - Product : PowerNode 6 port ( id : 0x0004 / type : 0x0003 / Version : 4) + 4 - Command classes : {'COMMAND_CLASS_MANUFACTURER_SPECIFIC', 'COMMAND_CLASS_ASSOCIATION', 'COMMAND_CLASS_NO_OPERATION', 'COMM + AND_CLASS_VERSION', 'COMMAND_CLASS_SWITCH_BINARY', 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 'COMMAND_CLASS_CRC_16_ENCAP', 'COMMA + ND_CLASS_PROTECTION', 'COMMAND_CLASS_CONFIGURATION', 'COMMAND_CLASS_BASIC', 'COMMAND_CLASS_METER', 'COMMAND_CLASS_SWITCH_ALL'} + 4 - Capabilities : {'listening', 'routing', 'beaming'} + 4 - Neighbors : {1} / Power level : None + 4 - Is sleeping : False / Can wake-up : False / Battery level : None + ------------------------------------------------------------ + Driver statistics : {'SOFCnt': 49, 'ACKWaiting': 0, 'readAborts': 0, 'badChecksum': 0, 'readCnt': 49, 'writeCnt': 46, 'CANCnt': + 0, 'NAKCnt': 1, 'ACKCnt': 30, 'OOFCnt': 0, 'dropped': 17, 'retries': 0, 'callbacks': 0, 'badroutes': 0, 'noack': 4, 'netbusy': + 0, 'nondelivery': 0, 'routedbusy': 0, 'broadcastReadCnt': 0, 'broadcastWriteCnt': 9} + ------------------------------------------------------------ + Stop network + Exit diff --git a/docs/README.rst b/docs/README.rst index d0d4537c..c4ae7c44 100755 --- a/docs/README.rst +++ b/docs/README.rst @@ -6,18 +6,18 @@ :target: https://circleci.com/gh/OpenZWave/python-openzwave :alt: Circle status -.. image:: https://img.shields.io/pypi/dm/python_openzwave.svg - :target: https://pypi.python.org/pypi/python_openzwave - :alt: Pypi downloads +.. image:: https://ci.appveyor.com/api/projects/status/2ogl8tx7o3pqphc9?svg=true + :target: https://ci.appveyor.com/project/bibi21000/python-openzwave + :alt: Appveyor status .. image:: https://img.shields.io/pypi/format/python_openzwave.svg :target: https://pypi.python.org/pypi/python_openzwave :alt: Pypi format -.. image:: https://img.shields.io/pypi/status/python_openzwave.svg - :target: https://pypi.python.org/pypi/python_openzwave - :alt: Pypi status - +.. image:: https://img.shields.io/badge/Documentation-ok-brightgreen.svg?style=flat + :target: http://openzwave.github.io/python-openzwave/index.html + :alt: Documentation + ================ python-openzwave ================ @@ -30,80 +30,79 @@ python-openzwave is a python wrapper for the openzwave c++ library : https://git * a full-event webapp example : flask + socket.io + jquery * a suite of tests * many examples - * `Full documentation `_ + * `Full documentation `_ -python-openzwave 0.4.0 is coming !!! -==================================== +python-openzwave 0.4.x is here !!! +================================== - - 0.4.0.x versions are for testers only. Don't use it in a production environement !!! +- New installation process via pip - - New installation process via pip - - - First, you need some build tools and libs. On ubuntu, you should use : +- First, you need some build tools and libs. On ubuntu, you should use : .. code-block:: bash sudo apt-get install --force-yes -y make libudev-dev g++ libyaml-dev - - Make your virtualenv and activate it : +- Make your virtualenv and activate it : .. code-block:: bash virtualenv --python=python3 venv3 source venv3/bin/activate - - Install the default (embed) flavor : +- Install the default flavor : .. code-block:: bash (venvX) pip install python_openzwave - - The previous command install python_openzwave statitically linked to sources downloaded from https://github.com/OpenZWave/python-openzwave/tree/master/archives. - You can change this using flavors. There is a bug in the package dependencies and flavors on some systems. You may need to install dependencies manualy : +- The previous command try to install python_openzwave with the flavor 'shared'. + If it can't find a precompiled library of openzwave, it will use the flavor 'embed' with sources downloaded from https://github.com/OpenZWave/python-openzwave/tree/master/archives. + You can change this using flavor option. + There is a bug in the package dependencies and flavors on some systems. You may need to install dependencies manualy : - - on python 2.7 : + - on python 2.7 : .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'Louie>=1.1' - - on python 3 : + - on python 3 : .. code-block:: bash - (venvX) pip install cython wheel six + (venvX) pip install cython wheel six pyserial (venvX) pip install 'PyDispatcher>=2.0.5' - - Choose your flavor : +- Choose your flavor : - embed : the default one. Download sources from https://github.com/OpenZWave/python-openzwave/tree/master/archives and build them. Python_openzwave is statically build using a cythonized version of libopenzwave. No need to install cython. - shared : if you have install openzwave as module manually, you can link python_openzwave to it. - git : download sources from openzwave github and link statically to it. - - embed_shared (experimental) : download sources from https://github.com/OpenZWave/python-openzwave/tree/master/archives, build and install as module on the system. + - embed_shared : download sources from https://github.com/OpenZWave/python-openzwave/tree/master/archives, build and install as module on the system. Python_openzwave use it. Need root access to install openzwave libs. - - git_shared (experimental) : download sources from openzwave github, build and install them as module on the system. + - git_shared : download sources from openzwave github, build and install them as module on the system. Python_openzwave use it. Need root access to install openzwave libs. - ozwdev and ozwdev_shared : use the dev branch of openzwave on github. - - dev : for python_openzwave developers - + - dev : for python_openzwave developers. Look for openzwave sources in a local folder specified by the LOCAL_OPENZWAVE environment variable (defaults to 'openzwave'). - - Install it : +- Install it : .. code-block:: bash - (venvX) pip install python_openzwave --install-option="--flavor=git" + (venvX) pip install python_openzwave --no-deps --install-option="--flavor=git" - - You can update to the last version of openzwave using the git flavor : - +- You can update to the last version of openzwave using the git flavor : + .. code-block:: bash (venvX) pip uninstall -y python_openzwave - (venvX) pip install python_openzwave --no-cache-dir --install-option="--flavor=git" + (venvX) pip install python_openzwave --no-cache-dir --no-deps --install-option="--flavor=git" - - At last, you can launch pyozw_check: +- At last, you can launch pyozw_check to test your installation : If no usb stick is connected to the machine, launch : @@ -164,6 +163,50 @@ python-openzwave 0.4.0 is coming !!! Try to destroy manager Try to destroy options + You can list the nodes on your network using : + + .. code-block:: bash + + (venvX) pyozw_check -l -d /dev/ttyUSB0 -t 60 + + .. code-block:: bash + + ------------------------------------------------------------------------------- + Define options for device /dev/ttyUSB0 + Start network + Wait for network (30s) + Network is ready + ------------------------------------------------------------------------------- + Controller capabilities : {'primaryController', 'staticUpdateController'} + Controller node capabilities : {'listening', 'primaryController', 'staticUpdateController', 'beaming'} + Nodes in network : 4 + Driver statistics : {'noack': 6, 'routedbusy': 0, 'readCnt': 115, 'ACKWaiting': 0, 'badChecksum': 0, 'broadcastReadCnt': 0, 'NAKCnt': 0, 'broadcastWriteCnt': 9, 'dropped': 0, 'CANCnt': 0, 'callbacks': 0, 'OOFCnt': 0, 'readAborts': 0, 'badroutes': 0, 'SOFCnt': 115, 'netbusy': 0, 'writeCnt': 49, 'nondelivery': 0, 'ACKCnt': 49, 'retries': 0} + ------------------------------------------------------------ + 1 - Name : ( Location : ) + 1 - Ready : True / Awake : True / Failed : False + 1 - Manufacturer : Aeotec ( id : 0x0086 ) + 1 - Product : DSA02203 Z-Stick S2 ( id : 0x0001 / type : 0x0002 ) + 1 - Version : 3 / Secured : False / Zwave+ : False + 1 - Command classes : {'COMMAND_CLASS_NO_OPERATION', 'COMMAND_CLASS_BASIC'} + 1 - Capabilities : {'staticUpdateController', 'listening', 'primaryController', 'beaming'} + 1 - Neigbors : {4} / Power level : None + 1 - Is sleeping : False / Can wake-up : False / Battery level : None + + ... + + ------------------------------------------------------------ + 4 - Name : ( Location : ) + 4 - Ready : True / Awake : True / Failed : False + 4 - Manufacturer : GreenWave ( id : 0x0099 ) + 4 - Product : PowerNode 6 port ( id : 0x0004 / type : 0x0003 ) + 4 - Version : 4 / Secured : False / Zwave+ : False + 4 - Command classes : {'COMMAND_CLASS_BASIC', 'COMMAND_CLASS_CONFIGURATION', 'COMMAND_CLASS_SWITCH_BINARY', 'COMMAND_CLASS_VERSION', 'COMMAND_CLASS_CRC_16_ENCAP', 'COMMAND_CLASS_MANUFACTURER_SPECIFIC', 'COMMAND_CLASS_ASSOCIATION', 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 'COMMAND_CLASS_METER', 'COMMAND_CLASS_PROTECTION', 'COMMAND_CLASS_NO_OPERATION', 'COMMAND_CLASS_SWITCH_ALL'} + 4 - Capabilities : {'listening', 'routing', 'beaming'} + 4 - Neigbors : {1} / Power level : None + 4 - Is sleeping : False / Can wake-up : False / Battery level : None + + ... + - The old manager is now available via the pyozw_shell command. You need to install module "urwid>=1.1.1" with pip before using it. @@ -197,15 +240,6 @@ python-openzwave 0.4.0 is coming !!! - Please report your successful installations here : https://github.com/OpenZWave/python-openzwave/issues/73 -python-openzwave 0.3.0 is out !!! -================================= - -Look at CHANGELOG to see new features and release notes. - -Look at INSTALL_REPO to test it now. - -Look at INSTALL_ARCH to install from archive : no need to install cython anymore. - Support ======= You can ask for support on the google group : http://groups.google.com/d/forum/python-openzwave-discuss. @@ -216,87 +250,3 @@ Pull requests ============= Please read DEVEL documentation before submitting pull request. A lot of project tasks are done automatically or with makefile, so they must be done in a certain place or in a special order. - -Migrating from python-openzwave 0.2.X to 0.3.0 -============================================== -I need to update source tree of python-openzwave and modules's names because of a bug in setuptools -: https://bitbucket.org/pypa/setuptools/issue/230/develop-mode-does-not-respect-src . -Sorry for that. - -Update your sources: - -.. code-block:: bash - - git pull - -Before building python-openzwave 0.3.0, you must uninstall the old version : - -.. code-block:: bash - - sudo make uninstall - -About cython : I've made many tests using cython installed via pip : (0.20, 0.21 and 0.22). -Compilation is ok but a segfault appears when launching the tests. Please remove it. - -.. code-block:: bash - - sudo pip uninstall Cython - -You also need to make some minor updates in you code, look at CHANGELOG - -If you have problems, please submit an issue with : - - - cython -V - - the content of the directory /usr/local/lib/python2.7/dist-packages/ (for python2.7) - - the content of /usr/local/lib/python2.7/dist-packages/easy-install.pth (for python 2.7) - - -Ubuntu 64bits ... and the others -================================ - -If you're using Ubuntu 64 bits (and mayde others) and keep your distribution up to date, -you certainly have the segfault problem. - -Ubuntu 12.04 and 14.04 seems to be affected by this bug. Ubuntu 15.10 and Debian Jessie not. - -It appears with the last update of python : - -.. code-block:: bash - - $ python - Python 2.7.6 (default, Jun 22 2015, 17:58:13) - [GCC 4.8.2] on linux2 - Type "help", "copyright", "credits" or "license" for more information. - - -I've open a discussion on cython-users here : https://groups.google.com/forum/#!topic/cython-users/mRsviGuCFOk - -The only way I found to avoid this is to rebuild and reinstall the old release of python : - -.. code-block:: bash - - wget https://launchpad.net/ubuntu/+archive/primary/+files/python2.7_2.7.6-8.dsc https://launchpad.net/ubuntu/+archive/primary/+files/python2.7_2.7.6.orig.tar.gz https://launchpad.net/ubuntu/+archive/primary/+files/python2.7_2.7.6-8.diff.gz - - dpkg-source -x python2.7_2.7.6-8.dsc - - sudo apt-get build-dep python2.7 - - cd python2.7-2.7.6 - - dpkg-buildpackage - -Wait, wait and await again :) - -.. code-block:: bash - - cd .. - - sudo dpkg -i *.deb - -To prevent future updates of python, you could mark its packages. For example, if you use apt to update your distribution, use the following command : - -.. code-block:: bash - - sudo apt-mark hold idle-python2.7 libpython2.7-minimal python2.7-dbg python2.7-minimal libpython2.7 libpython2.7-stdlib python2.7-dev libpython2.7-dbg libpython2.7-testsuite python2.7-doc libpython2.7-dev python2.7 python2.7-examples - -Some users have reported that building python-openzwave using the archive (INSTALL_ARCH) can also do the trick. Let me know if it works for you. diff --git a/docs/data.rst b/docs/data.rst index 3787f3a9..fcf7357e 100755 --- a/docs/data.rst +++ b/docs/data.rst @@ -12,4 +12,8 @@ The common data structures and defitions. .. autodata:: PyValueTypes .. autodata:: PyLogLevels .. autodata:: PyControllerCommand +.. autodata:: PyControllerError .. autodata:: PyControllerState +.. autodata:: PyOptionList +.. autodata:: PyStatDriver +.. autodata:: PyStatNode diff --git a/docs/index.rst b/docs/index.rst index 6d61c312..6cc2f303 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,9 +6,12 @@ Contents: .. toctree:: :maxdepth: 3 - The new "pyx". It provides a low level to the ZWave network. - And its data's definitions - The new API. Map a ZWave Network in objects. + The Readme. + Installation notes. + The low level library ("pyx") to the ZWave network. + The API. Map a ZWave Network in python objects. + How to submit a PR. + Changelog. Indices and tables diff --git a/docs/libopenzwave.rst b/docs/libopenzwave.rst index 7da30fbe..0dc35df6 100755 --- a/docs/libopenzwave.rst +++ b/docs/libopenzwave.rst @@ -5,3 +5,15 @@ libopenzwave module :members: :undoc-members: :show-inheritance: + +.. automodule:: libopenzwave +.. autodata:: PyNotifications +.. autodata:: PyGenres +.. autodata:: PyValueTypes +.. autodata:: PyLogLevels +.. autodata:: PyControllerCommand +.. autodata:: PyControllerError +.. autodata:: PyControllerState +.. autodata:: PyOptionList +.. autodata:: PyStatDriver +.. autodata:: PyStatNode diff --git a/examples/api_sniff.py b/examples/api_sniff.py index d8bb22af..53ce3e4f 100755 --- a/examples/api_sniff.py +++ b/examples/api_sniff.py @@ -41,7 +41,11 @@ from openzwave.network import ZWaveNetwork from openzwave.option import ZWaveOption import time -from louie import dispatcher, All +import six +if six.PY3: + from pydispatch import dispatcher +else: + from louie import dispatcher device="/dev/ttyUSB0" log="Debug" diff --git a/examples/hello_world.py b/examples/hello_world.py index 9886a67b..ef0a8402 100755 --- a/examples/hello_world.py +++ b/examples/hello_world.py @@ -41,7 +41,11 @@ from openzwave.network import ZWaveNetwork from openzwave.option import ZWaveOption import time -from louie import dispatcher, All +import six +if six.PY3: + from pydispatch import dispatcher +else: + from louie import dispatcher device="/dev/ttyUSB0" log="None" diff --git a/github_deploy_key_openzwave_python_openzwave.enc b/github_deploy_key_openzwave_python_openzwave.enc new file mode 100644 index 00000000..7084b6cb --- /dev/null +++ b/github_deploy_key_openzwave_python_openzwave.enc @@ -0,0 +1 @@ +gAAAAABaaPgox9_NS0MxF8CneeTVNKqVTLD4L9qfTWWYyzBzMjv5RMLlK6yaarYcvLo4tCPFM9o1i9QBatG5nWNzeyosiBCvft8wmYmua1rWLuAP2bGic3QgviCw75wvA677DDHfZ5w--spPJNfdUcmWlh0bONeBKi4kHFdTXKZ0snjciqAehF1vyc3YcnBIQEhZ0GZSxavbFeXhfgtf5ysw79-KIY295KbBmF1UpieDCE-LJiLxjIc027Qymw2gL-JSoRfCtFZRl9PD6E2MmEk2YWYuZhkxYMpTMmTouK8E70QKQXpfUX7M8yyidR_DXjyrNsReOC4gJtZhFkIMZZ7ic2WJ93SjSI7kCetHF-gE1sB-c89WVOH19htCldHj2_MeeXR0aF4dyC5-P2eHapMY0AHZo-A-z2AIeO9zmmiqFhu-PNQfkoq8bpfvGQgRRT20mDHbRxuwAQMYuoSyBaF35w7pEzPjJv3rmJO_3x4SLZoCZ6UBq-03TyMrpAF5hhycct79EjJGBhGXGAQiQNW2yeW1mpx9J4AsyJJ6INjfMvqYMdY8tQxsEO117HdwLh-R3qMlwl1B10_tmMDs5dwIphMkRgdEwHGFlE6hkBN5nDx3eH-AH5VaYxBaro8Z_wu6FzFFhMbSfJDq1x8b7uJRhk1K0DI1lqRKrcfAVrdW3r7WGodmUdi8TNk2_pYcPRAi-adYiN6QHUQTguJ0FWl3kvm3WOfR1-WPqfGSu6DCHGADTxMQFrl94vnCqEGtc7GLg27cuq72JMvcZqcu9bK39cu64d1UExzLd1slfjKya5dCCGt1t0PPxx4KtqRqzndgDSrF0csCViBZA4CUytDtUdQF79wi3pJckJoaNRCKzykg_Hmvg52POPtclRum3e70-yToxRsZRAEjMyVXs3jrYVGJvl7PtYydhvwVUq9BK5lQcXyyHnztgABLnIb7eYt5APIRAUC554Kx1hnsyUkSH1VgvFs7-I1ZiOSVq7-Vh1OksyfEkPnwKv86Z4rTAXQkw9JlKDh2VC0piVia_iwRwOBLat6KkVDRvcrEuSHtLaBnYj14hIY9rEZQks5cavDS3XoEVZhvcQag7FQDbCGMBVs1y0rw-IY8a3gyR1fegtHH6CuucS8FoWy1VPdTrniIfmYSpRJQFPMqt-wfrTXeYXa6jBxuspV8rh9w_a-hMMbr87KENqSsa18pPey9GmBHCUaIwmWcHKqtbzULtgeOQBo1aKcii6BLG91qE9ysexrXUcDUpl55PF_UfY_Nweyu_jwozjYV8_XO-RIjruDonni1OjO8-HdnlTdj-VBN13OqWPs7BWeNWJ11lxAlLn8L-ZaqAqO1fY-f_xJ0SCLLyK2_2Osvn51ZckngpZ_nyrQU5t0k39xhXiN5_lKXeU8KNsvZ5JO6t7iG6JctVwu-v7AZgKFw5UFfTj3QLj509fjzBUBHl0PVh8HgBtMScWCBAB7V_KDwFgY4JRFvQ1PTrk8Rm5QnlYKVKhrZAbrKwrB58stKk3azZgkWxbquYkv2ffZtCoVmmQUaXbIFgQ7JKSlF2DINoIztAu5M2e99YTQC-6j2eOkiEDqdk4lI5CTESnjSYtmVracoRhjnnLfskgSt04ec8Q4hymqKGFC1QYCgXYcU1H1umrYuchz9HwoHDIe51YVAf86rI1-grm8Z2baQUIoVA1n_1Jj6ENYEMpHPk6OjFu10tgSpSpTAgTUXpmsFspyPJzlD_ThqyebLOKr_iv3jJ8vkSOto1-fxAH9lNd9VM-HpQutxXcxilA6Kf5i3bMHktD_9h-dbg6akazaSe3uwIL5c7_OnKDsKOIbWRYpQ5hNKwquS02gOQCYiPuYokHL-XJMZHAkYUMDjAvgYy4awieSVQmaNo7HfZLJWfwWuE7cdz1lqkpDNnjkQ72cUbRq34bekvgrjEvDslqxmqjBAL2IBfacbpMxVm4pGTmjP3ZGvhIAizY-I_F_J5TlEJolpdmApRV-wfjCk7eZpOqFfUrOT9BRR22FYiXY1rMrFKxlvwCmBYbKtVNPaLaOjQJoRTtyc5iJc3kv0XcI_5fiAGciG87nFXd3IA9hO04N5jV5XKaMlVSCJ1jJdlre4wQuESiDtzaIY7-bAgrRocllIshZezf0aw9qQa-iXVsK7Ili8d-ewr9TL6CK2g5qjwMv5BvCvhYaV-kON7Jvk1buYg8GHuNSRJuzbHvEETihYASB2dPOGvSwtKw1imDnfbUYxYyC8fBNlbg4ttlDRYnlSNVYqn8LNqKaeuvrpP7xpEuTMB4KcloDJ8UuaUYM9ty_6evZBrL9FwSb5qj0p0mZ12O_NHgHvDqNX35DMC4GNqvV5iOhlOChCq92QRd2QhkwrgGpctPADOU1Wo8c8T44PkKxymeyjhJEXrbmlL5SdS2wV3HOu_TyjPXIEEdAv6Czex6VHbDR6fPOJAyiCdCwrraeElWqKMOYOLW-xlI9zS1TJUJXKez7QsEkoCJMk0htzpu_dF_pFk5u4RmTeXHH-KlVTDvxuQlnnT-lbRLz0XtukKtjGPyZHJbdCfbVgULRI-Z204NN91LRZ4E4MGjofTbLWIKU4CrxoQAcQeUh1xIGt2ZH4CoF3xsm46GuS65Wf5NPoqWGFZ8y_8vEMxuSJG6iaskiuQRnW_ikkHAws0RLcJh_gpdF0uShaSoO7zJXcdkYF75IDVaHJeIGIh7SDhVAE6rDnEpVLETd-5wm_zaLO-nJ1b6-qe0k_V4tQG24VdErF6IumXqUuDqwjT3Jy4-pR0Bd9_hd2wyOGZN6oo5tF3xz1IvY5i6GM1PH2P0qMnephzri7b9yJYFM5Y6PzjSY9sZC44rt6GlAHQ4nfzqLhCXR8dr6UYPPF1KKhpDL-WdUu6VxjEMUWVxxsNvcjJRC0ggTpu9uRtBqdRt_PRV0sKoSj3NLICg7ludePdpdw5w-Sx-rSm0c0xjROSlA-0mLHN2i4ZbOolyU1JpUqH2Zz22I10aofeBapxAiXfzLzle_M1ZmeWt8tqm4pEx0DjGVjtMNKhgLRaEgDcAgm6FNUA-W4KCysnLcC-J3l8xyhrZvDXW0KT7oUtwcJi1ZHXOJE6ZAVjMRjkFJJlkhCflTDjU0V1-Uue6yw-Moo9KHbq5uDGMKtzrj_zkpLIBIilZ_kTPSfZrfB5m2jR9Q1Pn07KRoXWKnSkqr9u8hHZ-kfpc_yi6Y7YI4ghENv15zDXRHO2WYKIpOe_biEbJ4djHariIBokXAEF8_lbFiMM_d0kTqYdXxGrJktwakh0hs2uO8PcXCMgNu0Oi23xPSqUPQjpLkNL_1VRkaMbQGVLW9EyBJfMLs7TFfmxcrJXqo5rEJ5gsx4O5B4syi9pM3HFxwPz2p5tsSrK6Cy5n-OYD-E4fpbE1a1xP5UZXRtpOFrL7OT48xQ9xTrsUq2sCR-e_JsGePWGJJrkTzDrpINSvYw8U94dGf23YvAJn03y2EmGU5NXNvsc9ize3a6uoKyA3swNP2FHvPuG16XjlHmySixLQPWQwtUn75q9sfN9XBgPzqwDY-KJrZXABp9iPuHHHxhttaNHXf15GY9rGbAMaTQ7SGDjSykXO-sUrFDmLsO1AsuvEHN1plV0kYYNY3DVP0uZ5vc3_P35RvdkRWfYV_oG6TnAHKgTVu18gdtD6Db7QhBP2LqxbYR9PQQ1U5vWFAbBLf1sst5O_Y5gIkmw4jd6lR_QXcBPvEWzdEc2Z3uLIVrgQxwAXfwOMWVTlkwV3bvP9pH_mGSdmWhDZQeXx06HaJaHMHYKM9oT_peXbSP1xPBxSu_qL7CBZYEOr72bAaU5xFmylENOKlfCxD7cx35zArbFJrHcG4AabBh3HSQE8xjpgzNVTAskWSiesknI5jYtzsvjTu0wEfSGikYHe_R_aKuSTiJotN6MExOhuOJt1CvCUWmVIKtfvyDFmW0MCRslIxdEtrSJfvQBMD0bsk1f6M9GiAdF3xoX2jeDCwp2Rn9gefUWwG-01nc6QbEUYC-frNp2w4x-2NFmiBirVLr9_Dbcg4TxWmArnjg85YfkIk_Iy8HtO-Lv0QJm4hcdyait6_AikTZlOIVkwwkedA42q7s5CisbY_53p9pmc2yeas6RwgPAgYX_8b1ipy8zbnjf28BCytEazeeGPqcFJR37dAkjQrbA-YK_PZV62xY6UlpVii9T4Bpd70jcnnJ4_TieSqPJNzypopJBKS2OlaN-vHLZ2i8iZ7OpA0ZjBJtRT8jyplsLi7GRIA9CJgBWnP_54udPGg4RFkwCNk5GodBVVKmaGqpHKp7_Q-0pIMVCASkktGx6g0NWP59SFJNUHejM9QgwhLlaB3CC8y1p2_57wAFhl07lTQdfhbFKz3053_obzBu8wJiCoQBI3sZXcs= \ No newline at end of file diff --git a/pyozw_progressbar.py b/pyozw_progressbar.py new file mode 100644 index 00000000..7ea4d0ce --- /dev/null +++ b/pyozw_progressbar.py @@ -0,0 +1,159 @@ +import sys +import os +import time +import datetime +import io +import threading + +try: + PY3 = not unicode +except NameError: + PY3 = True + +TEMPLATE = ( + '\r' + '{prefix} ' + '{percent}% ' + '{count} ' + 'Elapsed: 0{elapsed} ' + 'Remaining: {remaining} ' + '{file_name}' +) + + +def remap(value, old_min=0, old_max=0, new_min=0, new_max=0): + old_range = old_max - old_min + new_range = new_max - new_min + + return ( + int((((value - old_min) * new_range) / old_range)) + new_min + ) + + +print_lock = threading.Lock() + + +class ProgressBar(object): + + def __init__(self): + self.stdout = sys.stdout + sys.stdout = self + self.files = [] + self.count = 0 + self.start = None + self.prefix = '' + self.last_line_len = 0 + self.file_position = 0 + + def flush(self): + pass + + def isatty(self): + return True + + def close(self): + if self.start is not None: + print_lock.acquire() + if self.files: + self.update(50, 100, file_name=self.files[-1]) + else: + self.update(50, 100, file_name='') + + self.stdout.write('\n\n') + self.stdout.flush() + print_lock.release() + + sys.stdout = self.stdout + + def write(self, line): + if PY3: + try: + line = line.decode("utf-8") + except AttributeError: + pass + + if str('Build openzwave') in line: + print_lock.acquire() + self.stdout.write('\n') + self.stdout.flush() + + # try: + # self.file_position = self.stdout.tell() + # except (io.UnsupportedOperation, WindowsError): + # pass + + self.prefix = 'Build OpenZWave' + self.start = time.time() + self.update(0, 0, file_name='') + print_lock.release() + + elif self.start is not None: + if str('/errorReport:queue') in line: + print_lock.acquire() + files = line.split('/errorReport:queue ')[1] + self.files = [ + os.path.split(f)[1] for f in files.split(' ') + ] + self.count = len(self.files) + print_lock.release() + + elif line.strip() in self.files: + print_lock.acquire() + self.files.remove(line.strip()) + count = remap( + self.count - len(self.files), + old_max=self.count, + new_max=50 + ) + percent = remap( + self.count - len(self.files), + old_max=self.count, + new_max=100 + ) + + self.update(count, percent, line.strip()) + if not self.files: + self.update(50, 100, file_name='') + print_lock.release() + + def update(self, count, percent, file_name): + current = time.time() + elapsed = current - self.start + + percent = str(percent) + percent = ' ' * (3 - len(percent)) + percent + + if count: + time_per_file = elapsed / (self.count - len(self.files)) + remaining = time_per_file * len(self.files) + remaining = '0' + str(datetime.timedelta(seconds=int(remaining))) + else: + remaining = '99:99:99' + + line = TEMPLATE.format( + prefix=self.prefix, + percent=percent, + count='#' * count + ' ' * (50 - count), + elapsed=str(datetime.timedelta(seconds=int(elapsed))), + remaining=remaining, + file_name=file_name + ) + + # try: + # self.stdout.seek(self.file_position) + # self.stdout.truncate() + # except (io.UnsupportedOperation, WindowsError): + # pass + + if self.last_line_len: + self.stdout.write('\r' + ' ' * self.last_line_len) + + self.stdout.write(line) + self.stdout.flush() + self.last_line_len = len(line) + + def __getattr__(self, item): + if item in self.__dict__: + return self.__dict__[item] + + return getattr(self.stdout, item) diff --git a/pyozw_setup.py b/pyozw_setup.py old mode 100755 new mode 100644 index 81c6a0c6..b201840f --- a/pyozw_setup.py +++ b/pyozw_setup.py @@ -21,8 +21,8 @@ along with python-openzwave. If not, see http://www.gnu.org/licenses. Build process : -- ask user what to do (zmq way in pip) -- or parametrizes it +- ask user what to do (zmq way in pip) +- or parametrizes it --dev : use local sources and cythonize way (for python-openzwave devs, ...) --embed : use local sources and cpp file (for third parties packagers, ...) --git : download openzwave from git (for geeks) @@ -48,175 +48,175 @@ try: from wheel.bdist_wheel import bdist_wheel as _bdist_wheel except ImportError: - log.warn("ImportError in : from wheel.bdist_wheel import bdist_wheel as _bdist_wheel") + log.warn("ImportError in : from wheel.bdist_wheel import bdist_wheel as _bdist_wheel") from platform import system as platform_system import glob from pyozw_version import pyozw_version +try: + PY3 = not unicode +except NameError: + PY3 = True + LOCAL_OPENZWAVE = os.getenv('LOCAL_OPENZWAVE', 'openzwave') SETUP_DIR = os.path.dirname(os.path.abspath(__file__)) -def get_default_exts (): - exts = { "name": "libopenzwave", - "sources": [ ], - "include_dirs": [ ], - "define_macros": [ ( 'PY_LIB_VERSION', pyozw_version ) ], - "libraries": [ ], - "extra_objects": [ ], - "extra_compile_args": [ ], - "extra_link_args": [ ], - "language": "c++", - } - return exts - -def cython_context(): - try: - from Cython.Distutils import build_ext - except ImportError: - return None - exts = get_default_exts() - exts['define_macros'] += [('PY_SSIZE_T_CLEAN',1)] - exts['sources'] = ["src-lib/libopenzwave/libopenzwave.pyx"] - return exts - -def cpp_context(): - try: - from distutils.command.build_ext import build_ext - except ImportError: - return None - exts = get_default_exts() - exts['define_macros'] += [('PY_SSIZE_T_CLEAN',1)] - exts['sources'] = ["openzwave-embed/open-zwave-master/python-openzwave/src-lib/libopenzwave/libopenzwave.cpp"] - exts["include_dirs"] += [ "src-lib/libopenzwave/" ] - return exts - -def pybind_context(): - exts = get_default_exts() - exts["sources"] = [ "src-lib/libopenzwave/LibZWaveException.cpp", - "src-lib/libopenzwave/Driver.cpp", - "src-lib/libopenzwave/Group.cpp", - "src-lib/libopenzwave/Log.cpp", - "src-lib/libopenzwave/Options.cpp", - "src-lib/libopenzwave/Manager.cpp", - "src-lib/libopenzwave/Notification.cpp", - "src-lib/libopenzwave/Node.cpp", - "src-lib/libopenzwave/Values.cpp", - "src-lib/libopenzwave/libopenzwave.cpp" - ] - exts["include_dirs"] = [ "pybind11/include" ] - exts['extra_compile_args'] += [ "-fvisibility=hidden" ] - return exts - -def system_context(ctx, openzwave=None, static=False): - #System specific section - #~ os.environ["CC"] = "gcc" - #~ os.environ["CXX"] = "g++" - #~ os.environ["PKG_CONFIG_PATH"] = "PKG_CONFIG_PATH:/usr/local/lib/x86_64-linux-gnu/pkgconfig/" - log.info("Found platform {0}".format(sys.platform)) - if static: - ctx['include_dirs'] += [ - "{0}/cpp/src".format(openzwave), - "{0}/cpp/src/value_classes".format(openzwave), - "{0}/cpp/src/platform".format(openzwave) ] - if sys.platform.startswith("win"): - ctx['libraries'] += [ "setupapi", "msvcrt", "ws2_32", "dnsapi" ] +class Template(object): - if static: - ctx['extra_objects'] = [ "{0}/cpp/build/windows/vs2010/Release/openzwave.lib".format(openzwave) ] - ctx['include_dirs'] += [ "{0}/cpp/build/windows".format(openzwave) ] - else: - import pyozw_pkgconfig - ctx['libraries'] += [ "openzwave" ] - extra = pyozw_pkgconfig.cflags('libopenzwave') - if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + def __init__(self, openzwave=None, cleanozw=False, sysargv=None, flavor="embed", backend="cython"): + self.openzwave = openzwave + self._ctx = None + self.cleanozw = cleanozw + self.flavor = flavor + self.backend = backend + self.sysargv = sysargv + """Specifics options for os ie windows + """ + self.os_options = dict() + + def get_default_exts (self): + exts = { "name": "libopenzwave", + "sources": [ ], + "include_dirs": [ ], + "define_macros": [ ( 'PY_LIB_VERSION', pyozw_version ) ], + "libraries": [ ], + "extra_objects": [ ], + "extra_compile_args": [ ], + "extra_link_args": [ ], + "language": "c++", + } + return exts + + def cython_context(self): + try: + from Cython.Distutils import build_ext + except ImportError: + return None + exts = self.get_default_exts() + exts['define_macros'] += [('PY_SSIZE_T_CLEAN',1)] + exts['sources'] = ["src-lib/libopenzwave/libopenzwave.pyx"] + return exts - elif sys.platform.startswith("cygwin"): + def cpp_context(self): + try: + from distutils.command.build_ext import build_ext + except ImportError: + return None + exts = self.get_default_exts() + exts['define_macros'] += [('PY_SSIZE_T_CLEAN',1)] + exts['sources'] = ["openzwave-embed/open-zwave-master/python-openzwave/src-lib/libopenzwave/libopenzwave.cpp"] + exts["include_dirs"] += [ "src-lib/libopenzwave/" ] + return exts + + def pybind_context(self): + exts = self.get_default_exts() + exts["sources"] = [ "src-lib/libopenzwave/LibZWaveException.cpp", + "src-lib/libopenzwave/Driver.cpp", + "src-lib/libopenzwave/Group.cpp", + "src-lib/libopenzwave/Log.cpp", + "src-lib/libopenzwave/Options.cpp", + "src-lib/libopenzwave/Manager.cpp", + "src-lib/libopenzwave/Notification.cpp", + "src-lib/libopenzwave/Node.cpp", + "src-lib/libopenzwave/Values.cpp", + "src-lib/libopenzwave/libopenzwave.cpp" + ] + exts["include_dirs"] = [ "pybind11/include" ] + exts['extra_compile_args'] += [ "-fvisibility=hidden" ] + return exts + + def system_context(self, ctx, static=False): + #System specific section + #~ os.environ["CC"] = "gcc" + #~ os.environ["CXX"] = "g++" + #~ os.environ["PKG_CONFIG_PATH"] = "PKG_CONFIG_PATH:/usr/local/lib/x86_64-linux-gnu/pkgconfig/" + log.info("Found platform {0}".format(sys.platform)) if static: - ctx['libraries'] += [ "udev", "stdc++",'resolv' ] - ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(openzwave) ] - ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(openzwave) ] - else: - import pyozw_pkgconfig - ctx['libraries'] += [ "openzwave" ] - extra = pyozw_pkgconfig.cflags('libopenzwave') - if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + ctx['include_dirs'] += [ + "{0}/cpp/src".format(self.openzwave), + "{0}/cpp/src/value_classes".format(self.openzwave), + "{0}/cpp/src/platform".format(self.openzwave) ] - elif sys.platform.startswith("darwin") : - ctx['extra_link_args'] += [ "-framework", "CoreFoundation", "-framework", "IOKit" ] - ctx['extra_compile_args'] += [ "-stdlib=libc++", "-mmacosx-version-min=10.7" ] + if sys.platform.startswith("win"): + from pyozw_win import get_system_context + get_system_context(ctx, self.os_options, openzwave=os.path.abspath(self.openzwave), static=static) - if static: - ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(openzwave) ] - ctx['include_dirs'] += [ "{0}/cpp/build/mac".format(openzwave) ] - else: - import pyozw_pkgconfig - ctx['libraries'] += [ "openzwave" ] - extra = pyozw_pkgconfig.cflags('libopenzwave') - if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] - - elif sys.platform.startswith("freebsd"): - if static: - ctx['libraries'] += [ "usb", "stdc++" ] - ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(openzwave) ] - ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(openzwave) ] - else: - import pyozw_pkgconfig - ctx['libraries'] += [ "openzwave" ] - extra = pyozw_pkgconfig.cflags('libopenzwave') - if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] - - elif sys.platform.startswith("sunos"): - if static: - ctx['libraries'] += [ "udev", "stdc++",'resolv' ] - ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(openzwave) ] - ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(openzwave) ] - else: - import pyozw_pkgconfig - ctx['libraries'] += [ "openzwave" ] - extra = pyozw_pkgconfig.cflags('libopenzwave') - if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + elif sys.platform.startswith("cygwin"): + if static: + ctx['libraries'] += [ "udev", "stdc++",'resolv' ] + ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] + ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(self.openzwave) ] + else: + import pyozw_pkgconfig + ctx['libraries'] += [ "openzwave" ] + extra = pyozw_pkgconfig.cflags('libopenzwave') + if extra != '': + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] + + elif sys.platform.startswith("darwin") : + ctx['extra_link_args'] += [ "-framework", "CoreFoundation", "-framework", "IOKit" ] + ctx['extra_compile_args'] += [ "-stdlib=libc++", "-mmacosx-version-min=10.7" ] + + if static: + ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] + ctx['include_dirs'] += [ "{0}/cpp/build/mac".format(self.openzwave) ] + else: + import pyozw_pkgconfig + ctx['libraries'] += [ "openzwave" ] + extra = pyozw_pkgconfig.cflags('libopenzwave') + if extra != '': + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] - elif sys.platform.startswith("linux"): - if static: - ctx['libraries'] += [ "udev", "stdc++",'resolv' ] - ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(openzwave) ] - ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(openzwave) ] - else: - import pyozw_pkgconfig - ctx['libraries'] += [ "openzwave" ] - extra = pyozw_pkgconfig.cflags('libopenzwave') - if extra != '': - for ssubstitute in ['/', '/value_classes/', '/platform/']: - ctx['extra_compile_args'] += [ extra.replace('//', ssubstitute) ] + elif sys.platform.startswith("freebsd"): + os.environ["CPPFLAGS"] = "-Wno-unused-private-field" + if static: + ctx['libraries'] += [ "usb", "stdc++" ] + ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] + ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(self.openzwave) ] + else: + import pyozw_pkgconfig + ctx['libraries'] += [ "openzwave" ] + extra = pyozw_pkgconfig.cflags('libopenzwave') + if extra != '': + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] - else: - # Unknown systemm - raise RuntimeError("Can't detect plateform {0}".format(sys.platform)) + elif sys.platform.startswith("sunos"): + if static: + ctx['libraries'] += [ "usb-1.0", "stdc++",'resolv' ] + ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] + ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(self.openzwave) ] + else: + import pyozw_pkgconfig + ctx['libraries'] += [ "openzwave" ] + extra = pyozw_pkgconfig.cflags('libopenzwave') + if extra != '': + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] - return ctx + elif sys.platform.startswith("linux"): + if static: + ctx['libraries'] += [ "udev", "stdc++",'resolv' ] + ctx['extra_objects'] = [ "{0}/libopenzwave.a".format(self.openzwave) ] + ctx['include_dirs'] += [ "{0}/cpp/build/linux".format(self.openzwave) ] + else: + import pyozw_pkgconfig + ctx['libraries'] += [ "openzwave" ] + extra = pyozw_pkgconfig.cflags('libopenzwave') + if extra != '': + for ssubstitute in ['', 'value_classes', 'platform']: + ctx['extra_compile_args'] += [ os.path.normpath(os.path.join(extra, ssubstitute)) ] + + else: + # Unknown systemm + raise RuntimeError("Can't detect plateform {0}".format(sys.platform)) + + return ctx -class Template(object): - - def __init__(self, openzwave=None, cleanozw=False, sysargv=None, flavor="embed", backend="cython"): - self.openzwave = openzwave - self._ctx = None - self.cleanozw = cleanozw - self.flavor = flavor - self.backend = backend - self.sysargv = sysargv - @property def ctx(self): if self._ctx is None: @@ -232,7 +232,7 @@ def build_ext(self): current_template.install_minimal_dependencies() from Cython.Distutils import build_ext as _build_ext return _build_ext - + @property def copy_openzwave_config(self): return True @@ -252,18 +252,23 @@ def finalize_context(self, ctx): else: ctx['define_macros'] += [('PY_LIB_BACKEND', "cython")] return ctx - + def install_requires(self): - return ['Cython'] - + if sys.platform.startswith("win"): + return ['Cython'] + else: + return ['Cython==0.28.6'] + def build_requires(self): - return ['Cython'] - + if sys.platform.startswith("win"): + return ['Cython'] + else: + return ['Cython==0.28.6'] + def build(self): if len(self.ctx['extra_objects']) == 1 and os.path.isfile(self.ctx['extra_objects'][0]): log.info("Use cached build of openzwave") return True - log.info("Build openzwave ... be patient ...") from subprocess import Popen, PIPE from threading import Thread try: @@ -274,9 +279,16 @@ def build(self): io_q = Queue() def stream_watcher(identifier, stream): + # fixes subprocess output lag issue when using python 2.x - for line in stream: - io_q.put((identifier, line)) + if PY3: + dummy_return = b'' + else: + dummy_return = '' + + for line in iter(stream.readline, dummy_return): + if line: + io_q.put((identifier, line)) if not stream.closed: stream.close() @@ -296,23 +308,44 @@ def printer(): if identifier == 'STDERR': sys.stderr.write('{0}\n'.format(line)) log.error('{0}\n'.format(line)) + elif sys.platform.startswith("win"): + progress_bar.write(line) + + if sys.platform.startswith("win"): + progress_bar.close() if sys.platform.startswith("win"): - proc = Popen('make', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + from pyozw_progressbar import ProgressBar + from pyozw_win import get_clean_command, get_build_command + + cwd = os.path.split(self.os_options['solution_path'])[0] + build_command = get_build_command(**self.os_options) + + + log.info("Build openzwave ... be patient ...") + + progress_bar = ProgressBar() + proc = Popen(build_command, stdout=PIPE, stderr=PIPE, cwd=cwd) + elif sys.platform.startswith("cygwin"): + log.info("Build openzwave ... be patient ...") proc = Popen('make', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("darwin"): + log.info("Build openzwave ... be patient ...") proc = Popen('make', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("freebsd"): + log.info("Build openzwave ... be patient ...") proc = Popen('gmake', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("sunos"): - proc = Popen('make', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + log.info("Build openzwave ... be patient ...") + # fixed command issues to Popen + proc = Popen(['make', 'PREFIX=/opt/local'], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("linux"): + log.info("Build openzwave ... be patient ...") proc = Popen('make', stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) else: @@ -329,6 +362,7 @@ def printer(): while tprinter.is_alive(): time.sleep(1) tprinter.join() + return True def install_so(self): @@ -366,19 +400,19 @@ def printer(): sys.stderr.write('{0}\n'.format(line)) log.error('{0}\n'.format(line)) if sys.platform.startswith("win"): - proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + proc = Popen([ 'copy', 'OpenZWave.dll' , '%SYSTEM32%\\' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.os_options['vsproject_build'])) + elif sys.platform.startswith("cygwin"): proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("darwin"): proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("freebsd"): proc = Popen([ 'gmake', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("sunos"): - proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + proc = Popen([ 'make', 'PREFIX=/opt/local', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("linux"): proc = Popen([ 'make', 'install' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) @@ -397,45 +431,55 @@ def printer(): while tprinter.is_alive(): time.sleep(1) tprinter.join() - log.info("ldconfig openzwave so ... be patient ...") - try: + + if sys.platform.startswith("win"): + log.info("Register dll ... be patient ...") + proc = Popen([ 'regsvr32', 'OpenZWave.dll' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.os_options['vsproject_build'])) + + elif sys.platform.startswith("cygwin"): import pyozw_pkgconfig ldpath = pyozw_pkgconfig.libs_only_l('libopenzwave')[2:] log.info("ldconfig openzwave in {0} so ... be patient ...".format(ldpath)) - if sys.platform.startswith("win"): - proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - - elif sys.platform.startswith("cygwin"): - proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - - elif sys.platform.startswith("darwin"): - proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - - elif sys.platform.startswith("freebsd"): - proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - - elif sys.platform.startswith("sunos"): - proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - - elif sys.platform.startswith("linux"): - proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - else: - # Unknown systemm - raise RuntimeError("Can't detect plateform {0}".format(sys.platform)) + elif sys.platform.startswith("darwin"): + import pyozw_pkgconfig + ldpath = pyozw_pkgconfig.libs_only_l('libopenzwave')[2:] + log.info("ldconfig openzwave in {0} so ... be patient ...".format(ldpath)) + proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - Thread(target=stream_watcher, name='stdout-watcher', - args=('STDOUT', proc.stdout)).start() - Thread(target=stream_watcher, name='stderr-watcher', - args=('STDERR', proc.stderr)).start() + elif sys.platform.startswith("freebsd"): + import pyozw_pkgconfig + ldpath = pyozw_pkgconfig.libs_only_l('libopenzwave')[2:] + log.info("ldconfig openzwave in {0} so ... be patient ...".format(ldpath)) + proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - tprinter = Thread(target=printer, name='printer') - tprinter.start() - while tprinter.is_alive(): - time.sleep(1) - tprinter.join() - except Exception: - log.info("Can't launch ldconfig") + elif sys.platform.startswith("sunos"): + import pyozw_pkgconfig + ldpath = pyozw_pkgconfig.libs_only_l('libopenzwave')[2:] + log.info("ldconfig openzwave in {0} so ... be patient ...".format(ldpath)) + proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + + elif sys.platform.startswith("linux"): + import pyozw_pkgconfig + ldpath = pyozw_pkgconfig.libs_only_l('libopenzwave')[2:] + log.info("ldconfig openzwave in {0} so ... be patient ...".format(ldpath)) + proc = Popen([ 'ldconfig', ldpath ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + + else: + # Unknown systemm + raise RuntimeError("Can't detect plateform {0}".format(sys.platform)) + + Thread(target=stream_watcher, name='stdout-watcher', + args=('STDOUT', proc.stdout)).start() + Thread(target=stream_watcher, name='stderr-watcher', + args=('STDERR', proc.stderr)).start() + + tprinter = Thread(target=printer, name='printer') + tprinter.start() + while tprinter.is_alive(): + time.sleep(1) + tprinter.join() time.sleep(2.5) log.info("Openzwave so installed and loaded") tprinter = None @@ -444,11 +488,11 @@ def printer(): def clean(self): #Build openzwave try: - if not os.path.isfile(self.openzwave): + if not os.path.isdir(self.openzwave): return True except TypeError: return True - log.info("Clean openzwave ... be patient ...") + log.info("Clean openzwave in %s ... be patient ..." % (self.openzwave) ) from subprocess import Popen, PIPE from threading import Thread try: @@ -481,21 +525,32 @@ def printer(): if identifier == 'STDERR': sys.stderr.write('{0}\n'.format(line)) log.error('{0}\n'.format(line)) - + proc = None if sys.platform.startswith("win"): - proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + from pyozw_win import get_clean_command + clean_command = get_clean_command(**self.os_options) + log.info("Clean openzwave project ... be patient ...") + proc = Popen( + clean_command, + stdout=PIPE, + stderr=PIPE, + cwd=os.path.split(self.os_options['solution_path'])[0] + ) + #~ proc.wait() + #~ proc = Popen([ 'regsvr32', '-u', 'OpenZWave.dll' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(os.path.abspath(self.openzwave))) + #~ proc = Popen([ 'del', '/F', '/Q', '/S', '%SYSTEM32%\OpenZWave.dll' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(os.path.abspath(self.openzwave))) + elif sys.platform.startswith("cygwin"): proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("darwin"): proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("freebsd"): proc = Popen([ 'gmake', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) - + elif sys.platform.startswith("sunos"): - proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) + proc = Popen([ 'make', 'PREFIX=/opt/local', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) elif sys.platform.startswith("linux"): proc = Popen([ 'make', 'clean' ], stdout=PIPE, stderr=PIPE, cwd='{0}'.format(self.openzwave)) @@ -504,19 +559,21 @@ def printer(): # Unknown systemm raise RuntimeError("Can't detect plateform {0}".format(sys.platform)) - Thread(target=stream_watcher, name='stdout-watcher', - args=('STDOUT', proc.stdout)).start() - Thread(target=stream_watcher, name='stderr-watcher', - args=('STDERR', proc.stderr)).start() + if proc is not None: + Thread(target=stream_watcher, name='stdout-watcher', + args=('STDOUT', proc.stdout)).start() + Thread(target=stream_watcher, name='stderr-watcher', + args=('STDERR', proc.stderr)).start() - tprinter = Thread(target=printer, name='printer') - tprinter.start() - while tprinter.is_alive(): - time.sleep(1) - tprinter.join() + tprinter = Thread(target=printer, name='printer') + tprinter.start() + while tprinter.is_alive(): + time.sleep(1) + tprinter.join() return True def clean_all(self): + log.info("Clean-all openzwave ... be patient ...") try: from pkg_resources import resource_filename dirn = resource_filename('python_openzwave.ozw_config', '__init__.py') @@ -536,17 +593,26 @@ def clean_all(self): return self.clean() def check_minimal_config(self): - log.info("Found g++ : {0}".format(find_executable("g++"))) - log.info("Found gcc : {0}".format(find_executable("gcc"))) - log.info("Found make : {0}".format(find_executable("make"))) - log.info("Found gmake : {0}".format(find_executable("gmake"))) - exe = find_executable("pkg-config") - log.info("Found pkg-config : {0}".format(exe)) - if exe is not None: - import pyozw_pkgconfig - for lib in self.ctx['libraries'] + ['yaml-0.1', 'libopenzwave', 'python', 'python2', 'python3']: - log.info("Found library {0} : {1}".format(lib, pyozw_pkgconfig.exists(lib))) - + if sys.platform.startswith("win"): + log.info("Found MSBuild.exe : {0}".format(self.os_options['msbuild_path'])) + log.info("Found arch : {0}".format(self.os_options['arch'])) + log.info("Found build configuration : {0}".format(self.os_options['build_type'])) + log.info("Found Visual Studio project : {0}".format(self.os_options['solution_path'])) + log.info("Found build path : {0}".format(self.os_options['build_path'])) + log.info("Found cython : {0}".format(find_executable("cython"))) + else: + log.info("Found g++ : {0}".format(find_executable("g++"))) + log.info("Found gcc : {0}".format(find_executable("gcc"))) + log.info("Found make : {0}".format(find_executable("make"))) + log.info("Found gmake : {0}".format(find_executable("gmake"))) + log.info("Found cython : {0}".format(find_executable("cython"))) + exe = find_executable("pkg-config") + log.info("Found pkg-config : {0}".format(exe)) + if exe is not None: + import pyozw_pkgconfig + for lib in self.ctx['libraries'] + ['yaml-0.1', 'libopenzwave', 'python', 'python2', 'python3']: + log.info("Found library {0} : {1}".format(lib, pyozw_pkgconfig.exists(lib))) + def install_minimal_dependencies(self): if len(self.build_requires()) == 0: return @@ -568,7 +634,7 @@ def install_minimal_dependencies(self): log.info("Minimal dependencies already installed {0}".format(pyreq)) except Exception: log.warn("Can't get package list from pip.") - + def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/master'): #Get openzwave """download an archive to a specific location""" @@ -576,10 +642,10 @@ def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zi dest_file = os.path.join(dest, 'open-zwave.zip') if os.path.exists(self.openzwave): if not self.cleanozw: - log.info("Already have directory %s. Use it. Use --cleanozw to clean it.", self.openzwave) + #~ log.info("Already have directory %s. Use it. Use --cleanozw to clean it.", self.openzwave) return self.openzwave else: - log.info("Already have directory %s but remove and clean it as asked", self.openzwave) + #~ log.info("Already have directory %s but remove and clean it as asked", self.openzwave) self.clean_all() try: os.remove(dest_file) @@ -607,51 +673,59 @@ def clean_openzwave_so(self): for path in ['/usr/local/etc/openzwave', '/usr/local/include/openzwave', '/usr/local/share/doc/openzwave']: try: log.info('Try to remove {0}'.format('/usr/local/etc/openzwave')) - shutil.rmtree(os.path.abspath(self.openzwave)) + shutil.rmtree(self.openzwave) except Exception: pass return True - + def clean_cython(self): try: os.remove('src-lib/libopenzwave/libopenzwave.cpp') except Exception: pass - + class DevTemplate(Template): - + def __init__(self, **args): Template.__init__(self, **args) def get_context(self): opzw_dir = LOCAL_OPENZWAVE if LOCAL_OPENZWAVE is None: - return None + if sys.platform.startswith("win"): + from pyozw_win import get_openzwave + get_openzwave('openzwave') + else: + return None + if not os.path.isdir(opzw_dir): - log.error("Can't find {0}".format(opzw_dir)) - return None + if sys.platform.startswith("win"): + from pyozw_win import get_openzwave + get_openzwave(opzw_dir) + else: + return None self.openzwave = opzw_dir - ctx = cython_context() + ctx = self.cython_context() if ctx is None: log.error("Can't find Cython") return None - ctx = system_context(ctx, openzwave=opzw_dir, static=True) + ctx = self.system_context(ctx, static=True) return ctx def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/master'): return True class GitTemplate(Template): - + def __init__(self, **args): Template.__init__(self, openzwave=os.path.join("openzwave-git", 'open-zwave-master'), **args) def get_context(self): - ctx = cython_context() + ctx = self.cython_context() if ctx is None: log.error("Can't find Cython") return None - ctx = system_context(ctx, openzwave=self.openzwave, static=True) + ctx = self.system_context(ctx, static=True) return ctx def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/master'): @@ -659,31 +733,31 @@ def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zi def clean_all(self): ret = self.clean() - dest,tail = os.path.split(os.path.abspath(self.openzwave)) + dest,tail = os.path.split(self.openzwave) if tail == "openzwave-git": try: log.info('Try to remove {0}'.format(self.openzwave)) - if os.path.isdir(os.path.abspath(self.openzwave)): - shutil.rmtree(os.path.abspath(self.openzwave)) + if os.path.isdir(self.openzwave): + shutil.rmtree(self.openzwave) except Exception: pass elif tail == 'open-zwave-master': try: log.info('Try to remove {0}'.format(dest)) - if os.path.isdir(os.path.abspath(dest)): - shutil.rmtree(os.path.abspath(dest)) + if os.path.isdir(dest): + shutil.rmtree(dest) except Exception: pass return ret class GitSharedTemplate(GitTemplate): - + def get_context(self): - ctx = cython_context() + ctx = self.cython_context() if ctx is None: log.error("Can't find Cython") return None - ctx = system_context(ctx, openzwave=self.openzwave, static=False) + ctx = self.system_context(ctx, static=False) while '' in ctx['extra_compile_args']: ctx['extra_compile_args'].remove('') extra = '-I/usr/local/include/openzwave//' @@ -695,7 +769,7 @@ def get_context(self): @property def copy_openzwave_config(self): - return False + return sys.platform.startswith("win") @property def install_openzwave_so(self): @@ -706,23 +780,22 @@ def clean(self): return GitTemplate.clean(self) class OzwdevTemplate(GitTemplate): - + def __init__(self, **args): Template.__init__(self, openzwave=os.path.join("openzwave-git", 'open-zwave-Dev'), **args) - + def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/Dev'): return Template.get_openzwave(self, url) - class OzwdevSharedTemplate(GitSharedTemplate): - + def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/Dev'): return Template.get_openzwave(self, url) class EmbedTemplate(Template): - - def __init__(self, **args): - Template.__init__(self, openzwave=os.path.join("openzwave-embed", 'open-zwave-master'), **args) + + def __init__(self, backend='cpp', **args): + Template.__init__(self, openzwave=os.path.join("openzwave-embed", 'open-zwave-master'), backend=backend, **args) @property def build_ext(self): @@ -733,8 +806,8 @@ def build_ext(self): return _build_ext def get_context(self): - ctx = cpp_context() - ctx = system_context(ctx, openzwave=self.openzwave, static=True) + ctx = self.cpp_context() + ctx = self.system_context(ctx, static=True) return ctx def install_requires(self): @@ -747,7 +820,7 @@ def get_openzwave(self, url='https://raw.githubusercontent.com/OpenZWave/python- ret = Template.get_openzwave(self, url) shutil.copyfile(os.path.join(self.openzwave,'python-openzwave','openzwave.vers.cpp'), os.path.join(self.openzwave,'cpp','src','vers.cpp')) return ret - + def clean(self): ret = Template.clean(self) try: @@ -759,26 +832,26 @@ def clean(self): def clean_all(self): ret = self.clean() - dest,tail = os.path.split(os.path.abspath(self.openzwave)) + dest,tail = os.path.split(self.openzwave) if tail == "openzwave-embed": try: log.info('Try to remove {0}'.format(self.openzwave)) - shutil.rmtree(os.path.abspath(self.openzwave)) + shutil.rmtree(self.openzwave) except Exception: pass elif tail == 'open-zwave-master': try: log.info('Try to remove {0}'.format(dest)) - shutil.rmtree(os.path.abspath(dest)) + shutil.rmtree(dest) except Exception: pass return ret - + class EmbedSharedTemplate(EmbedTemplate): def get_context(self): - ctx = cpp_context() - ctx = system_context(ctx, openzwave=self.openzwave, static=False) + ctx = self.cpp_context() + ctx = self.system_context(ctx, static=False) while '' in ctx['extra_compile_args']: ctx['extra_compile_args'].remove('') extra = '-I/usr/local/include/openzwave//' @@ -799,17 +872,17 @@ def copy_openzwave_config(self): @property def install_openzwave_so(self): return True - + class SharedTemplate(Template): def __init__(self, **args): Template.__init__(self, **args) def get_context(self): - ctx = cython_context() + ctx = self.cython_context() if ctx is None: log.error("Can't find Cython") return None - ctx = system_context(ctx, static=False) + ctx = self.system_context(ctx, static=False) return ctx def build(self): @@ -817,7 +890,7 @@ def build(self): @property def copy_openzwave_config(self): - return False + return sys.platform.startswith("win") def get_openzwave(self, url='https://codeload.github.com/OpenZWave/open-zwave/zip/master'): return True @@ -828,11 +901,11 @@ def parse_template(sysargv): if '--flavor=dev' in sysargv: index = sysargv.index('--flavor=dev') flavor = sysargv.pop(index) - tmpl = DevTemplate(sysargv=sysargv) + tmpl = DevTemplate(sysargv=sysargv) elif '--flavor=git' in sysargv: index = sysargv.index('--flavor=git') flavor = sysargv.pop(index) - tmpl = GitTemplate(sysargv=sysargv) + tmpl = GitTemplate(sysargv=sysargv) elif '--flavor=git_shared' in sysargv: index = sysargv.index('--flavor=git_shared') flavor = sysargv.pop(index) @@ -840,7 +913,7 @@ def parse_template(sysargv): elif '--flavor=ozwdev' in sysargv: index = sysargv.index('--flavor=ozwdev') flavor = sysargv.pop(index) - tmpl = OzwdevTemplate(sysargv=sysargv) + tmpl = OzwdevTemplate(sysargv=sysargv) elif '--flavor=ozwdev_shared' in sysargv: index = sysargv.index('--flavor=ozwdev_shared') flavor = sysargv.pop(index) @@ -858,20 +931,39 @@ def parse_template(sysargv): flavor = sysargv.pop(index) tmpl = SharedTemplate(sysargv=sysargv) if tmpl is None: - #Default template flavor = 'embed' - tmpl = EmbedTemplate(sysargv=sysargv) + try: + import pyozw_pkgconfig + if pyozw_pkgconfig.exists('libopenzwave'): + try: + from Cython.Distutils import build_ext + flavor = 'shared' + except ImportError: + log.info("Can't find cython") + except: + log.info("Can't find pkg-config") + #Default template + if flavor == 'embed': + log.info("Use embeded package of openzwave") + tmpl = EmbedTemplate(sysargv=sysargv) + elif flavor == 'shared': + log.info("Use precompiled library openzwave") + tmpl = SharedTemplate(sysargv=sysargv) tmpl.flavor = flavor if '--cleanozw' in sysargv: index = sysargv.index('--cleanozw') sysargv.pop(index) tmpl.cleanozw = True + log.info('sysargv', sysargv) + print('sysargv', sysargv) + log.info("Found SETUP_DIR : {0}".format(SETUP_DIR)) + print("Found SETUP_DIR : {0}".format(SETUP_DIR)) return tmpl - + current_template = parse_template(sys.argv) def install_requires(): - pkgs = ['six'] + pkgs = ['six', 'pyserial'] if (sys.version_info > (3, 0)): pkgs.append('PyDispatcher>=2.0.5') else: @@ -879,8 +971,11 @@ def install_requires(): pkgs += current_template.install_requires() return pkgs +def build_requires(): + return current_template.build_requires() + def get_dirs(base): - return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ] + return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ] def data_files_config(target, source, pattern): ret = list() @@ -902,21 +997,21 @@ def run(self): build_openzwave.develop = True self.run_command('build_openzwave') _bdist_egg.run(self) - + class build_openzwave(setuptools.Command): - description = 'download an build openzwave' - + description = 'download and build openzwave' + user_options = [ ('openzwave-dir=', None, 'the source directory where openzwave sources should be stored'), ('flavor=', None, 'the flavor of python_openzwave to install'), ] - + def initialize_options(self): self.openzwave_dir = None self.flavor = None - + def finalize_options(self): if self.openzwave_dir is None: if getattr(self, 'develop', False) or not getattr(self, 'install', False): @@ -926,31 +1021,32 @@ def finalize_options(self): build.ensure_finalized() self.openzwave_dir = os.path.join(build.build_lib, current_template.openzwave) self.flavor = current_template.flavor - + def run(self): current_template.check_minimal_config() current_template.get_openzwave() + current_template.clean() current_template.build() if current_template.install_openzwave_so: current_template.install_so() class openzwave_config(setuptools.Command): description = 'Install config files from openzwave' - + user_options = [ ('install-dir=', None, 'the installation directory where openzwave configuration should be stored'), ] - + def initialize_options(self): self.install_dir = None - + def finalize_options(self): if self.install_dir is None: install = self.distribution.get_command_obj('install') install.ensure_finalized() self.install_dir = install.install_lib - + def run(self): if self.install_dir is None: log.warning("Can't install ozw_config to None") @@ -958,11 +1054,19 @@ def run(self): if not current_template.copy_openzwave_config: log.info("Don't install ozw_config for template {0}".format(current_template)) return + log.info("Install ozw_config for template {0}".format(current_template)) dest = os.path.join(self.install_dir, 'python_openzwave', "ozw_config") + if os.path.isdir(dest): + #Try to remove old config + try: + import shutil + shutil.rmtree(dest) + except Exception: + log.exception("Can't remove old config directory") if not os.path.isdir(dest): os.makedirs(dest) self.copy_tree(os.path.join(current_template.openzwave,'config'), dest) - + class build(_build): sub_commands = [('build_openzwave', None)] + _build.sub_commands @@ -984,25 +1088,25 @@ def run(self): current_template.clean_all() else: current_template.clean() - _clean.run(self) + _clean.run(self) class develop(_develop): - description = 'De velop python_openzwave' - + description = 'Develop python_openzwave' + user_options = _develop.user_options + [ ('flavor=', None, 'the flavor of python_openzwave to install'), ] - + def initialize_options(self): self.flavor = None return _develop.initialize_options(self) - + def finalize_options(self): if self.flavor is None: self.flavor = current_template.flavor log.info('flavor {0}'.format(self.flavor)) return _develop.finalize_options(self) - + def run(self): #In case of --uninstall, it will build openzwave to remove it ... stupid. #In develop mode, build is done by the makefile @@ -1013,21 +1117,21 @@ def run(self): class install(_install): description = 'Install python_openzwave' - + user_options = _install.user_options + [ ('flavor=', None, 'the flavor of python_openzwave to install'), ] - + def initialize_options(self): self.flavor = None return _install.initialize_options(self) - + def finalize_options(self): if self.flavor is None: self.flavor = current_template.flavor log.info('flavor {0}'.format(self.flavor)) return _install.finalize_options(self) - + def run(self): build_openzwave = self.distribution.get_command_obj('build_openzwave') build_openzwave.develop = True diff --git a/pyozw_version.py b/pyozw_version.py index 2306b6b1..4b4d3e8b 100644 --- a/pyozw_version.py +++ b/pyozw_version.py @@ -21,7 +21,7 @@ along with python-openzwave. If not, see http://www.gnu.org/licenses. """ -pyozw_version = '0.4.0.35' +pyozw_version = '0.4.19' if "-" in pyozw_version: pyozw_version_short = pyozw_version.split("-") else: diff --git a/pyozw_win.py b/pyozw_win.py new file mode 100644 index 00000000..3f052ace --- /dev/null +++ b/pyozw_win.py @@ -0,0 +1,802 @@ +# -*- coding: utf-8 -*- +""" +This file is part of **python-openzwave** project https://github.com/OpenZWave/python-openzwave. + :platform: Unix, Windows, MacOS X + :sinopsis: openzwave API + +.. moduleauthor: bibi21000 aka Sébastien GALLET + +License : GPL(v3) + +**python-openzwave** is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +**python-openzwave** is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with python-openzwave. If not, see http://www.gnu.org/licenses. + +""" + +import sys +import os +import platform +import shutil +from pyozw_version import pyozw_version + +try: + _winreg = __import__('_winreg') +except ImportError: + _winreg = __import__('winreg') + + +from subprocess import Popen, PIPE + +# this is simply to show that you can build using only VS2017 as a requirement. +VS2017_VCVARSALL = r'"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat"' + +WIN64 = '64' in platform.machine() +PYTHON64 = platform.architecture()[0] == '64bit' and WIN64 +ARCH = 'x64' if PYTHON64 else 'x86' + + +try: + PY3 = not unicode +except NameError: + PY3 = True + +TOOLSETS = { + 15.0: ['v141', '15.0'], # vs2017 + 14.0: ['v140', '14.0'], # vs2015 + 10.0: ['v100', '4.0'], # vs2010 + 4.0: ['v90', '4.0'], # vs2008 +} + + +def setup_build_env_2017(): + proc = Popen( + VS2017_VCVARSALL + ' ' + ARCH + ' && set', + shell=True, + stdout=PIPE, + stderr=PIPE + ) + + test_env = {} + for line in proc.stdout: + if PY3: + line = line.decode("utf-8") + + if '=' in line: + key, value = line.split('=', 1) + test_env[key.strip()] = value.strip() + + for key, value in list(test_env.items()): + if str(os.environ.get(key, None)) != value: + os.environ[key] = value + + os.environ['DISTUTILS_USE_SDK'] = '1' + + +# comment this line to run normally. +setup_build_env_2017() + + +def _get_reg_value(path, key): + d = _read_reg_values(path) + if key in d: + return d[key] + return '' + + +def _read_reg_keys(key): + try: + handle = _winreg.OpenKeyEx( + _winreg.HKEY_LOCAL_MACHINE, + 'SOFTWARE\\Wow6432Node\\Microsoft\\' + key + ) + except _winreg.error: + return [] + res = [] + + for i in range(_winreg.QueryInfoKey(handle)[0]): + res += [_winreg.EnumKey(handle, i)] + + return res + + +def _read_reg_values(key): + try: + handle = _winreg.OpenKeyEx( + _winreg.HKEY_LOCAL_MACHINE, + 'SOFTWARE\\Wow6432Node\\Microsoft\\' + key + ) + except _winreg.error: + return {} + res = {} + for i in range(_winreg.QueryInfoKey(handle)[1]): + name, value, _ = _winreg.EnumValue(handle, i) + res[_convert_mbcs(name)] = _convert_mbcs(value) + + return res + + +def _convert_mbcs(s): + dec = getattr(s, "decode", None) + if dec is not None: + try: + s = dec("mbcs") + except UnicodeError: + pass + return s + + +def get_environment(): + from setuptools.msvc import ( + msvc9_query_vcvarsall, + EnvironmentInfo, + msvc14_get_vc_env + ) + + py_version = sys.version_info[:2] + + if py_version >= (3, 5): + env = msvc14_get_vc_env(ARCH) + msbuild_version = 14.0 + env_info = EnvironmentInfo(ARCH) + msbuild_path = _find_file( + 'MSBuild.exe', + env_info.MSBuild[0] + )[0] + + sdks = ('10.0', '8.1', '8.1A', '8.0', '8.0A') + solution_dest = 'vs2015' + + elif (3, 5) > py_version >= (3, 3): + env = msvc9_query_vcvarsall(10.0, ARCH) + msbuild_version = 4.0 + msbuild_path = _get_reg_value( + 'MSBuild\\4.0', + 'MSBuildOverrideTasksPath' + ) + + if msbuild_path: + msbuild_path = _find_file( + 'MSBuild.exe', + msbuild_path + )[0] + + sdks = ('7.1', '7.0A') + solution_dest = 'vs2010' + + elif (3, 3) > py_version >= (2, 6): + env = msvc9_query_vcvarsall(9.0, ARCH) + msbuild_version = 4.0 + msbuild_path = _get_reg_value( + 'MSBuild\\4.0', + 'MSBuildOverrideTasksPath' + ) + + if msbuild_path: + msbuild_path = _find_file( + 'MSBuild.exe', + msbuild_path + )[0] + + sdks = ('6.1', '6.1A', '6.0A') + solution_dest = 'vs2008' + + else: + raise RuntimeError( + 'This library does not support python versions < 2.6' + ) + + for sdk in sdks: + sdk_version = _get_reg_value( + 'Microsoft SDKs\\Windows\\v' + sdk, + 'ProductVersion' + ) + if sdk_version: + sdk_installation_folder = _get_reg_value( + 'Microsoft SDKs\\Windows\\v' + sdk, + 'InstallationFolder' + ) + target_platform = sdk_version + os.environ['WindowsSdkDir'] = sdk_installation_folder + break + else: + raise RuntimeError('Unable to locate suitable SDK %s' % (sdks,)) + + platform_toolset, tools_version = TOOLSETS[msbuild_version] + + return ( + env, + msbuild_version, + msbuild_path, + sdk_installation_folder, + target_platform, + platform_toolset, + tools_version, + solution_dest + ) + + +def _find_file(file_name, path): + res = [] + + for root, dirs, files in os.walk(path): + if ( + ((PYTHON64 and 'amd64' in root) or 'amd64' not in root) and + file_name in files + ): + res.append(os.path.join(root, file_name)) + return res + + +def setup_build_environment(openzwave, build_type): + if 'DISTUTILS_USE_SDK' in os.environ: + target_platform = os.environ['WINDOWSSDKVERSION'].replace('\\', '') + + if 'VS150COMNTOOLS' in os.environ: + msbuild_version = 15.0 + solution_dest = 'vs2017' + + elif 'VS140COMNTOOLS' in os.environ: + msbuild_version = 14.0 + solution_dest = 'vs2015' + else: + raise RuntimeError + + msbuild_path = _find_file('MSBuild.exe', os.environ['VSINSTALLDIR'])[0] + platform_toolset, tools_version = TOOLSETS[msbuild_version] + sdk_installation_folder = os.environ['WINDOWSSDKVERBINPATH'] + os.environ['MSSDK'] = sdk_installation_folder + + else: + ( + env, + msbuild_version, + msbuild_path, + sdk_installation_folder, + target_platform, + platform_toolset, + tools_version, + solution_dest + ) = get_environment() + + if 'WINDOWSSDKVERBINPATH' in env: + sdk_installation_folder = env['WINDOWSSDKVERBINPATH'] + + env['MSSDK'] = sdk_installation_folder + env['DISTUTILS_USE_SDK'] = '1' + + for key, value in env.items(): + os.environ[key] = value + + if 'VS150COMNTOOLS' in os.environ and msbuild_version == 14.0: + platform_toolset = 'v141' + tools_version = '15.0' + msbuild_version = 15.0 + solution_dest = 'vs2017' + + if 'WINDOWSSDKLIBVERSION' in os.environ: + target_platform = ( + os.environ['WINDOWSSDKLIBVERSION'].replace('\\', '') + ) + + if not msbuild_path: + raise RuntimeError( + 'Unable to locate MSBuild to compile OpenZWave' + ) + + project_base_path = os.path.abspath( + os.path.join( + openzwave, + 'cpp', + 'build', + 'windows' + ) + ) + + project_path = os.path.join(project_base_path, solution_dest) + + if PYTHON64: + build_path = os.path.join(project_path, 'x64', build_type) + else: + build_path = os.path.join(project_path, build_type) + + if not os.path.exists(project_path): + shutil.copytree( + os.path.join(project_base_path, 'vs2010'), + project_path + ) + + print('Updating VS solution please wait.') + + if update_vs_project( + os.path.join(project_path, 'OpenZWave.vcxproj'), + tools_version, + platform_toolset, + target_platform + ): + with open(os.path.join(project_path, 'OpenZWave.sln'), 'r') as f: + sln = str(f.read()).replace('\r', '') + + if GLOBAL_SELECTION_TEMPLATE not in sln: + sln = sln.replace( + GLOBAL_SELECTION_KEY, + GLOBAL_SELECTION_TEMPLATE + ) + + with open(os.path.join(project_path, 'OpenZWave.sln'), 'w') as f: + f.write(sln) + + solution_path = os.path.join(project_path, 'OpenZWave.sln') + + return ( + solution_path, + build_path, + msbuild_path, + msbuild_version, + target_platform, + platform_toolset, + tools_version, + sdk_installation_folder + ) + + +def update_vs_project(path, tools_version, platform_toolset, target_platform): + from xml.etree import ElementTree + + vcxproj_xmlns = 'http://schemas.microsoft.com/developer/msbuild/2003' + ElementTree.register_namespace('', vcxproj_xmlns) + + with open(path, 'r') as f: + vcxproj = f.read() + + # the original xml file contains some characters that the xml parser + # does not like, these are non human readable characters and they do not + # need to exist. So we remove them. + for char in (187, 191, 239): + vcxproj = vcxproj.replace(chr(char), '') + + root = ElementTree.fromstring(vcxproj) + + vcxproj_xmlns = '{' + vcxproj_xmlns + '}' + + # there are only 3 things that need to get changed once the solution has + # been fully updated. the tools version, the platform teeolset + # and the windows target platform. if a cached version of openzwave is used + # there is no need to create a whole new solution. so what we do is we set + # an attribute in the root of the xml to inform us if the file has been + # upgraded already. + + root.attrib['ToolsVersion'] = tools_version + + for node in root.findall(vcxproj_xmlns + 'PropertyGroup'): + if ( + 'Label' in node.attrib and + node.attrib['Label'] == 'Configuration' + ): + for sub_node in node: + if ( + sub_node.tag.replace(vcxproj_xmlns, '') == + 'PlatformToolset' + ): + sub_node.text = platform_toolset + break + else: + sub_node = ElementTree.Element('PlatformToolset') + sub_node.text = platform_toolset + node.append(sub_node) + + for node in root.findall(vcxproj_xmlns + 'PropertyGroup'): + if 'Label' in node.attrib and node.attrib['Label'] == 'Globals': + for sub_node in node: + if ( + sub_node.tag.replace(vcxproj_xmlns, '') == + 'WindowsTargetPlatformVersion' + ): + sub_node.text = target_platform + break + else: + sub_node = ElementTree.Element('WindowsTargetPlatformVersion') + sub_node.text = target_platform + node.append(sub_node) + + # this function is the core of upgrading the solution. It burrows down + # into a node through each layer and makes a copy. this copy gets modified + # to become an x64 version. the copy gets returned and then added to the + # xml file + + def iter_node(old_node): + new_node = ElementTree.Element(old_node.tag) + if old_node.text is not None: + new_node.text = old_node.text.replace('Win32', 'x64') + + for key, value in old_node.attrib.items(): + new_node.attrib[key] = value.replace('Win32', 'x64') + for old_sub_node in old_node: + new_node.append(iter_node(old_sub_node)) + return new_node + + # here is the testing to se if the file has been updated before. + if 'PythonOpenZWave' not in root.attrib: + update = True + root.attrib['PythonOpenZWave'] = 'True' + i = 0 + + for node in root[:]: + tag = node.tag.replace(vcxproj_xmlns, '') + + if ( + tag == 'ItemGroup' and + 'Label' in node.attrib and + node.attrib['Label'] == 'ProjectConfigurations' + ): + for sub_item in node[:]: + node.append(iter_node(sub_item)) + + if ( + tag == 'PropertyGroup' and + 'Label' in node.attrib and + node.attrib['Label'] == 'Configuration' + ): + root.insert(i, iter_node(node)) + i += 1 + + if ( + tag == 'ImportGroup' and + 'Label' in node.attrib and + node.attrib['Label'] == 'PropertySheets' + ): + root.insert(i, iter_node(node)) + i += 1 + + if ( + tag == 'PropertyGroup' and + not node.attrib.keys() + ): + j = 0 + for sub_item in node[:]: + if ( + sub_item.tag.replace(vcxproj_xmlns, '') != + '_ProjectFileVersion' + ): + node.insert(j, iter_node(sub_item)) + j += 1 + + if tag == 'ItemDefinitionGroup': + root.insert(i, iter_node(node)) + i += 1 + i += 1 + else: + update = False + + with open(path, 'w')as f: + f.write(xml_tostring(root, vcxproj_xmlns)) + + # we return if the file was updated or not. this is a flag that tells up + # if we need to update the sln file. + return update + + +# this is a custom xml writer. it recursively iterates through an +# ElementTree object creating a formatted string that is as close as i can +# get it to what Visual Studio creates. I did this for consistency as well +# as ease of bug testing + +def xml_tostring(node, xmlns, indent=''): + tag = node.tag.replace(xmlns, '') + no_text = node.text is None or not node.text.strip() + + if indent: + output = '' + else: + output = '\n' + if xmlns: + node.attrib['xmlns'] = xmlns.replace('{', '').replace('}', '') + + if no_text and not list(node) and not node.attrib.keys(): + output += '{0}<{1} />\n'.format(indent, tag) + else: + output += '{0}<{1}'.format(indent, tag) + + for key in sorted(node.attrib.keys()): + output += ' {0}="{1}"'.format(key, str(node.attrib[key])) + + if not list(node) and no_text: + output += ' />\n' + elif not no_text and not list(node): + output += '>{0}\n'.format(node.text, tag) + elif list(node) and no_text: + output += '>\n' + for item in node: + output += xml_tostring(item, xmlns, indent + ' ') + output += '{0}\n'.format(indent, tag) + else: + output += '>\n {0}{1}\n'.format(indent, node.text) + for item in node: + output += xml_tostring(item, xmlns, indent + ' ') + output += '{0}\n'.format(indent, tag) + return output + + +# because we no longer use devenv in favor of msbuild there are only 2 commands +# needed. +# one for clean and the other to build +def get_clean_command(msbuild_path, solution_path, build_type, arch, **_): + clean_template = ( + '"{msbuild_path}" ' + '"{solution_path}" ' + '/property:Configuration={build_type} ' + '/property:Platform={arch} ' + '/t:Clean ' + ) + clean_command = clean_template.format( + msbuild_path=msbuild_path, + solution_path=solution_path, + build_type=build_type, + arch=arch + ) + + return clean_command + + +def get_build_command(msbuild_path, solution_path, build_type, arch, **_): + build_template = ( + '"{msbuild_path}" ' + '"{solution_path}" ' + '/property:Configuration={build_type} ' + '/property:Platform={arch} ' + '/t:Build' + ) + + build_command = build_template.format( + msbuild_path=msbuild_path, + solution_path=solution_path, + build_type=build_type, + arch=arch + ) + + return build_command + + +def get_system_context( + ctx, + options, + openzwave="openzwave", + static=False, + debug=False +): + + + if debug: + print("get_system_context for windows") + + # one feature i added is building a debugging version, this is only going + # to happen if sys.executable ends with _d which identifies that the python + # interpreter is a debugging build. + + if static: + if os.path.splitext(sys.executable)[0].endswith('_d'): + options['build_type'] = 'Debug' + ctx['define_macros'] += [('_DEBUG', 1)] + ctx['libraries'] += ["setupapi", "msvcrtd", "ws2_32", "dnsapi"] + else: + options['build_type'] = 'Release' + ctx['libraries'] += ["setupapi", "msvcrt", "ws2_32", "dnsapi"] + else: + if os.path.splitext(sys.executable)[0].endswith('_d'): + options['build_type'] = 'DebugDLL' + ctx['define_macros'] += [('_DEBUG', 1)] + ctx['libraries'] += ["setupapi", "msvcrtd", "ws2_32", "dnsapi"] + else: + options['build_type'] = 'ReleaseDLL' + ctx['libraries'] += ["setupapi", "msvcrt", "ws2_32", "dnsapi"] + + if PYTHON64: + options['arch'] = "x64" + else: + options['arch'] = 'Win32' + + ( + solution_path, + build_path, + msbuild_path, + msbuild_version, + target_platform, + platform_toolset, + tools_version, + sdk_installation_folder + ) = setup_build_environment(openzwave, options['build_type']) + + options['msbuild_path'] = msbuild_path + options['solution_path'] = solution_path + options['build_path'] = build_path + options['msbuild_version'] = msbuild_version + options['target_platform'] = target_platform + options['platform_toolset'] = platform_toolset + options['tools_version'] = tools_version + options['sdk_installation_folder'] = sdk_installation_folder + + if debug: + print('Platform: %s' % target_platform) + print('Platform architecture %s' % ARCH) + print('Platform toolset: %s' % platform_toolset) + print('MSBuild path: %s' % msbuild_path) + print('MSBuild version: %0.1f' % msbuild_version) + print('MSBuild tools version: %s' % tools_version) + print('SDK installation path: %s' % sdk_installation_folder) + print("Found options %s" % options) + + cpp_path = os.path.join(openzwave, 'cpp') + src_path = os.path.join(cpp_path, 'src') + + if static: + ctx['extra_objects'] = [os.path.join(build_path, 'OpenZWave.lib')] + + ctx['include_dirs'] += [ + src_path, + os.path.join(src_path, 'value_classes'), + os.path.join(src_path, 'platform'), + os.path.join(cpp_path, 'build', 'windows'), + build_path, + ] + else: + ctx['libraries'] += ["OpenZWave"] + + ctx['extra_compile_args'] += [ + src_path, + os.path.join(src_path, 'value_classes'), + os.path.join(src_path, 'platform'), + ] + + ctx['define_macros'] += [ + ('CYTHON_FAST_PYCCALL', 1), + ('_MT', 1), + ('_DLL', 1) + ] + + +GLOBAL_SELECTION_TEMPLATE = ''' Debug|x64 = Debug|x64 + DebugDLL|x64 = DebugDLL|x64 + Release|x64 = Release|x64 + ReleaseDLL|x64 = ReleaseDLL|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|x64.ActiveCfg = Debug|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Debug|x64.Build.0 = Debug|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.DebugDLL|x64.Build.0 = DebugDLL|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|x64.ActiveCfg = Release|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.Release|x64.Build.0 = Release|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 + {497F9828-DEC2-4C80-B9E0-AD066CCB587C}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64''' + + +GLOBAL_SELECTION_KEY = ''' EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution''' + + +def get_openzwave(opzw_dir): + url = 'https://codeload.github.com/OpenZWave/open-zwave/zip/master' + + from io import BytesIO + try: + from urllib2 import urlopen + except ImportError: + from urllib.request import urlopen + + import zipfile + + base_path = os.path.dirname(__file__) + + print('Downloading openzwave...') + + req = urlopen(url) + dest_file = BytesIO(req.read()) + dest_file.seek(0) + + zip_ref = zipfile.ZipFile(dest_file, 'r') + zip_ref.extractall(base_path) + zip_ref.close() + dest_file.close() + + os.rename( + os.path.join(base_path, zip_ref.namelist()[0]), + opzw_dir + ) + + +if __name__ == '__main__': + from subprocess import Popen, PIPE + from setuptools import setup + from distutils.extension import Extension + + print("Start pyozw_win") + + ctx = dict( + name='libopenzwave', + sources=['src-lib\\libopenzwave\\libopenzwave.pyx'], + include_dirs=['src-lib\\libopenzwave'], + define_macros=[ + ('PY_LIB_VERSION', pyozw_version), + ('PY_SSIZE_T_CLEAN', 1), + ('PY_LIB_FLAVOR', 'dev'), + ('PY_LIB_BACKEND', 'cython') + ], + libraries=[], + extra_objects=[], + extra_compile_args=[], + extra_link_args=[], + language='c++' + ) + + ozw_path = os.path.abspath('openzwave') + + if not os.path.exists(ozw_path): + get_openzwave('openzwave') + + options = dict() + + get_system_context( + ctx, + options, + openzwave=ozw_path, + static=True, + debug=True + ) + + clean = get_clean_command(**options) + build = get_build_command(**options) + + def run(command): + print('Running command:', command) + proc = Popen( + command, + shell=True, + stdout=PIPE, + stderr=PIPE, + cwd=os.path.split(options['solution_path'])[0], + ) + + if PY3: + dummy_return = b'' + else: + dummy_return = '' + + for line in iter(proc.stdout.readline, dummy_return): + if line and PY3: + sys.stdout.write(line.decode("utf-8")) + elif line: + sys.stdout.write(line) + + errcode = proc.returncode + print('\n\nerrcode', errcode, '\n\n') + + for line in iter(proc.stderr.readline, dummy_return): + if line and PY3: + sys.stdout.write(line.decode("utf-8")) + elif line: + sys.stdout.write(line) + + # run(clean) + # run(build) + + print( + 'Library built in %s using compiler %s for arch %s' % + (options['build_path'], options['msbuild_path'], options['arch']) + ) + + setup( + script_args=['build_ext'], + version=pyozw_version, + name='libopenzwave', + description='libopenzwave', + verbose=1, + ext_modules=[Extension(**ctx)], + ) diff --git a/setup-lib.py b/setup-lib.py index a7ea7181..ab9f22a5 100755 --- a/setup-lib.py +++ b/setup-lib.py @@ -36,7 +36,6 @@ from pyozw_version import pyozw_version from pyozw_setup import LOCAL_OPENZWAVE, SETUP_DIR from pyozw_setup import current_template, parse_template, get_dirs, data_files_config, install_requires -from pyozw_setup import get_default_exts, cython_context, cpp_context, pybind_context, system_context, cython_context from pyozw_setup import Template, DevTemplate, GitTemplate, EmbedTemplate, SharedTemplate from pyozw_setup import bdist_egg, build_openzwave, openzwave_config, build, clean, develop, install @@ -49,7 +48,7 @@ author='Sébastien GALLET aka bibi2100 ', author_email='bibi21000@gmail.com', version = pyozw_version, - scripts=['src-lib/scripts/pyozw_check'], + #~ scripts=['src-lib/scripts/pyozw_check'], zip_safe = False, url='https://github.com/OpenZWave/python-openzwave', cmdclass = {'build_ext': current_template.build_ext, @@ -67,7 +66,7 @@ package_dir = {'' : 'src-lib'}, #The following line install config drectory in share/python-openzwave #~ data_files = data_files, - packages = find_packages('src-lib', exclude=["scripts"]), + packages = find_packages('src-lib'), install_requires = install_requires(), ) diff --git a/setup-manager.py b/setup-manager.py index a819d572..5e3403d5 100644 --- a/setup-manager.py +++ b/setup-manager.py @@ -34,8 +34,8 @@ url='https://github.com/OpenZWave/python-openzwave', version = pyozw_version.pyozw_version, zip_safe = False, - scripts=['src-manager/scripts/pyozw_shell'], + #~ scripts=['src-manager/scripts/pyozw_shell'], package_dir = {'' : 'src-manager' }, - packages = find_packages('src-manager', exclude=["scripts"]), + packages = find_packages('src-manager'), install_requires=pyozw_version.install_requires() + [ "urwid>=1.1.1"], ) diff --git a/setup.py b/setup.py index 3c4c9868..7d17e584 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- """ This file is part of **python-openzwave** project https://github.com/OpenZWave/python-openzwave. - :platform: Unix, Windows, MacOS X + :platform: Unix, Windows, MacOS X, BSD .. moduleauthor:: bibi21000 aka Sébastien GALLET @@ -34,8 +34,7 @@ from distutils.extension import Extension from pyozw_version import pyozw_version from pyozw_setup import LOCAL_OPENZWAVE, SETUP_DIR -from pyozw_setup import current_template, parse_template, get_dirs, data_files_config, install_requires -from pyozw_setup import get_default_exts, cython_context, cpp_context, pybind_context, system_context, cython_context +from pyozw_setup import current_template, parse_template, get_dirs, data_files_config, install_requires, build_requires from pyozw_setup import Template, DevTemplate, GitTemplate, EmbedTemplate, SharedTemplate from pyozw_setup import bdist_egg, build_openzwave, openzwave_config, build, clean, develop, install @@ -58,9 +57,11 @@ 'openzwave_config': openzwave_config, 'clean': clean, 'develop': develop, - 'install': install + 'install': install, }, - scripts=['src-lib/scripts/pyozw_check', 'src-manager/scripts/pyozw_shell'], + #~ scripts=['src-lib/scripts/pyozw_check', 'src-manager/scripts/pyozw_shell'], + entry_points={'console_scripts':['pyozw_check=python_openzwave.scripts.pyozw_check:main', + 'pyozw_shell=python_openzwave.scripts.pyozw_shell:main'] }, ext_modules = [ Extension(**current_template.ctx) ], @@ -85,6 +86,7 @@ "Topic :: Home Automation", "Topic :: System :: Hardware", "Topic :: System :: Hardware :: Hardware Drivers", + "Topic :: Software Development :: Libraries :: Python Modules", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", diff --git a/src-api/openzwave/command.py b/src-api/openzwave/command.py index a9d7d34f..4b6d330c 100755 --- a/src-api/openzwave/command.py +++ b/src-api/openzwave/command.py @@ -835,7 +835,7 @@ def set_thermostat_heating(self, value): """ logger.debug(u"set_thermostat_heating value:%s", value) for v in self.get_thermostats(): - if self.values[v].command_class == 0x43 and self.values[v].label == 'Heating 1': + if self.values[v].command_class == 0x43 and self.values[v].label in ('Heating 1', 'Heating'): self.values[v].data = value return True return False @@ -852,7 +852,7 @@ def set_thermostat_cooling(self, value): """ logger.debug(u"set_thermostat_cooling value:%s", value) for v in self.get_thermostats(): - if self.values[v].command_class == 0x43 and self.values[v].label == 'Cooling 1': + if self.values[v].command_class == 0x43 and self.values[v].label in ('Cooling 1', 'Cooling'): self.values[v].data = value return True return False diff --git a/src-api/openzwave/controller.py b/src-api/openzwave/controller.py index 044ad4d1..745740a9 100755 --- a/src-api/openzwave/controller.py +++ b/src-api/openzwave/controller.py @@ -24,15 +24,22 @@ along with python-openzwave. If not, see http://www.gnu.org/licenses. """ -import sys +import os, sys import six if six.PY3: from pydispatch import dispatcher + from urllib.request import urlopen else: from louie import dispatcher + from urllib2 import urlopen +import zipfile +import tempfile +import threading +import shutil +import time + from openzwave.object import ZWaveObject, deprecated from libopenzwave import PyStatDriver, PyControllerState -import threading # Set default logging handler to avoid "No handler found" warnings. import logging @@ -326,6 +333,17 @@ def library_version(self): """ return self._network.manager.getLibraryVersion(self._network.home_id) + @property + def python_library_flavor(self): + """ + The flavor of the python library. + + :return: The python library flavor + :rtype: str + + """ + return self._network.manager.getPythonLibraryFlavor() + @property def python_library_version(self): """ @@ -337,6 +355,23 @@ def python_library_version(self): """ return self._network.manager.getPythonLibraryVersionNumber() + @property + def python_library_config_version(self): + """ + The version of the config for python library. + + :return: The python library config version + :rtype: str + + """ + tversion = "Original %s" % self.library_version + fversion = os.path.join(self.library_config_path, 'pyozw_config.version') + if os.path.isfile(fversion): + with open(fversion, 'r') as f: + val = f.read() + tversion = "Git %s" % val + return tversion + @property def ozw_library_version(self): """ @@ -1050,6 +1085,7 @@ def to_dict(self, extras=['all']): ret["zw_description"] = self.library_description ret["oz_version"] = self.ozw_library_version ret["py_version"] = self.python_library_version + ret["py_config_version"] = self.python_library_config_version return ret @deprecated @@ -1316,3 +1352,58 @@ def zwcallback(self, args): dispatcher.send(self.SIGNAL_CONTROLLER, \ **{'state': state, 'message': message, 'network': self._network, 'controller': self}) + + def update_ozw_config(self): + """ + Update the openzwave config from github. + Not available for shared flavor as we don't want to update the config of the precompiled config. + + """ + if self.python_library_flavor in ['shared']: + logger.warning(u"Can't update_ozw_config for this flavor (%s)."%self.python_library_flavor) + return + logger.info(u'Update_ozw_config from github.') + dest = tempfile.mkdtemp() + dest_file = os.path.join(dest, 'open-zwave.zip') + try: + req = urlopen('https://codeload.github.com/OpenZWave/open-zwave/zip/master') + with open(dest_file, 'wb') as f: + f.write(req.read()) + zip_ref = zipfile.ZipFile(dest_file, 'r') + zip_ref.extractall(dest) + zip_ref.close() + except Exception: + logger.exception("Can't get zip from github. Cancelling") + try: + shutil.rmtree(dest) + except Exception: + pass + + if os.path.isdir(self.library_config_path): + #Try to remove old config + try: + shutil.rmtree(self.library_config_path) + except Exception: + logger.exception("Can't remove old config directory") + + try: + shutil.copytree(os.path.join(dest, 'open-zwave-master', 'config'), self.library_config_path) + except Exception: + logger.exception("Can't copy to %s", self.library_config_path) + + try: + with open(os.path.join(self.library_config_path, 'pyozw_config.version'), 'w') as f: + f.write(time.strftime("%Y-%m-%d %H:%M")) + except Exception: + logger.exception("Can't update %s", os.path.join(self.library_config_path, 'pyozw_config.version')) + + try: + with open(os.path.join(self.library_config_path, '__init__.py'), 'a') as f: + f.write("#This file is part of **python-openzwave** project https://github.com/OpenZWave/python-openzwave.") + except Exception: + logger.exception("Can't create %s", os.path.join(self.library_config_path, '__init__.py')) + + shutil.rmtree(dest) + + + diff --git a/src-api/openzwave/group.py b/src-api/openzwave/group.py index 177c3992..22c96d62 100755 --- a/src-api/openzwave/group.py +++ b/src-api/openzwave/group.py @@ -44,7 +44,7 @@ class ZWaveGroup(ZWaveObject): Also used to retrieve information about the library, ... """ - def __init__(self, group_index, network=None, node_id=None): + def __init__(self, group_index, network, node_id): """ Initialize driver object diff --git a/src-api/openzwave/network.py b/src-api/openzwave/network.py index 42bb3ba0..91fa48b9 100755 --- a/src-api/openzwave/network.py +++ b/src-api/openzwave/network.py @@ -30,11 +30,10 @@ import six if six.PY3: from pydispatch import dispatcher - import _thread as thread else: from louie import dispatcher - import thread import threading + import libopenzwave import openzwave from openzwave.object import ZWaveException, ZWaveTypeException, ZWaveObject @@ -43,7 +42,6 @@ from openzwave.option import ZWaveOption from openzwave.scene import ZWaveScene from openzwave.singleton import Singleton -import json # Set default logging handler to avoid "No handler found" warnings. import logging @@ -304,8 +302,8 @@ def __init__(self, options, log=None, autostart=True, kvals=True): :type log: :param autostart: should we start the network. :type autostart: bool - :param autostart: Enable kvals (use pysqlite) - :type autostart: bool + :param kvals: Enable kvals (use pysqlite) + :type kvals: bool """ logger.debug("Create network object.") diff --git a/src-api/openzwave/node.py b/src-api/openzwave/node.py index d60f8582..1c399d80 100755 --- a/src-api/openzwave/node.py +++ b/src-api/openzwave/node.py @@ -24,6 +24,7 @@ """ import sys +from libopenzwave import PyStatNode from openzwave.object import ZWaveObject from openzwave.group import ZWaveGroup from openzwave.value import ZWaveValue @@ -249,6 +250,8 @@ def capabilities(self): caps.add('security') if self.is_beaming_device: caps.add('beaming') + if self.is_zwave_plus: + caps.add('zwave_plus') if self.node_id == self._network.controller.node_id: for cap in self._network.controller.capabilities: caps.add(cap) @@ -1053,3 +1056,45 @@ def type(self): :rtype: str """ return self._network.manager.getNodeType(self.home_id, self.object_id) + + @property + def stats(self): + """ + Retrieve statistics for node. + + Statistics: + + * sentCnt : Number of messages sent from this node. + * sentFailed : Number of sent messages failed + * retries : Number of message retries + * receivedCnt : Number of messages received from this node. + * receivedDups : Number of duplicated messages received; + * receivedUnsolicited : Number of messages received unsolicited + * lastRequestRTT : Last message request RTT + * lastResponseRTT : Last message response RTT + * sentTS : Last message sent time + * receivedTS : Last message received time + * averageRequestRTT : Average Request round trip time. + * averageResponseRTT : Average Response round trip time. + * quality : Node quality measure + * lastReceivedMessage[254] : Place to hold last received message + * errors : Count errors for dead node detection + + :return: Statistics of the node + :rtype: dict() + + """ + return self._network.manager.getNodeStatistics(self.home_id, self.object_id) + + def get_stats_label(self, stat): + """ + Retrieve label of the statistic for node. + + :param stat: The code of the stat label to retrieve. + :type stat: + :return: The label or the stat. + :rtype: str + + """ + #print "stat = %s" % stat + return PyStatNode[stat] diff --git a/src-api/openzwave/option.py b/src-api/openzwave/option.py index 74571f46..7fc68990 100755 --- a/src-api/openzwave/option.py +++ b/src-api/openzwave/option.py @@ -43,6 +43,32 @@ def emit(self, record): logger = logging.getLogger('openzwave') logger.addHandler(NullHandler()) + +VENDOR_IDS = ('0658',) + + +def _get_z_stick(): + try: + import serial.tools.list_ports + except ImportError: + return None + + for port in serial.tools.list_ports.comports(include_links=False): + if port.vid is None: + continue + if port.product is not None and 'Zigbee' in port.product: + continue + if port.interface is not None and 'Zigbee' in port.interface: + continue + if port.description is not None and 'Zigbee' in port.description: + continue + + for vid in VENDOR_IDS: + if vid.upper() == hex(port.vid)[2:].upper().zfill(4): + return port.device + return None + + class ZWaveOption(libopenzwave.PyOptions): """ Represents a Zwave option used to start the manager. @@ -52,7 +78,7 @@ def __init__(self, device=None, config_path=None, user_path=None, cmd_line=None) """ Create an option object and check that parameters are valid. - :param device: The device to use + :param device: The device to use or None for auto detection (pyserial needs to be installed for auto detection). :type device: str :param config_path: The openzwave config directory. If None, try to configure automatically. :type config_path: str @@ -62,7 +88,13 @@ def __init__(self, device=None, config_path=None, user_path=None, cmd_line=None) :type cmd_line: str """ + if device is None: + device = _get_z_stick() + if platform_system() == 'Windows': + if device and not device.startswith('\\\\.\\'): + device = '\\\\.\\' + device + self._device = device else: #For linux diff --git a/src-api/openzwave/scene.py b/src-api/openzwave/scene.py index 2d5a722e..5911c9b8 100755 --- a/src-api/openzwave/scene.py +++ b/src-api/openzwave/scene.py @@ -42,7 +42,7 @@ class ZWaveScene(ZWaveObject): Represents a single scene within the Z-Wave Network """ - def __init__(self, scene_id, network=None): + def __init__(self, scene_id, network): """ Initialize zwave scene diff --git a/src-lib/libopenzwave/libopenzwave.pyx b/src-lib/libopenzwave/libopenzwave.pyx index 43678c46..2753a7d5 100644 --- a/src-lib/libopenzwave/libopenzwave.pyx +++ b/src-lib/libopenzwave/libopenzwave.pyx @@ -354,6 +354,24 @@ PyStatDriver = { 'broadcastWriteCnt' : "Number of broadcasts sent", } +PyStatNode = { + 'sentCnt' : "Number of messages sent from this node", + 'sentFailed' : "Number of sent messages failed", + 'retries' : "Number of message retries", + 'receivedCnt' : "Number of messages received from this node", + 'receivedDups' : "Number of duplicated messages received", + 'receivedUnsolicited' : "Number of messages received unsolicited", + 'lastRequestRTT' : "Last message request RTT", + 'lastResponseRTT' : "Last message response RTT", + 'sentTS' : "Last message sent time", + 'receivedTS' : "Last message received time", + 'averageRequestRTT' : "Average Request round trip time", + 'averageResponseRTT' : "Average Response round trip time", + 'quality' : "Node quality measure", + 'lastReceivedMessage' : "Place to hold last received message", + 'errors' : "Count errors for dead node detection", + } + PyLogLevels = { 'Invalid' : {'doc':'Invalid Log Status', 'value':0}, 'None' : {'doc':'Disable all logging', 'value':1}, @@ -1061,7 +1079,7 @@ sleeping) have been polled, an "AllNodesQueried" notification is sent. 0x56: 'COMMAND_CLASS_CRC_16_ENCAP', 0x5A: 'COMMAND_CLASS_DEVICE_RESET_LOCALLY', 0x5B: 'COMMAND_CLASS_CENTRAL_SCENE', - 0x5E: 'COMMAND_CLASS_ZWAVE_PLUS_INFO', + 0x5E: 'COMMAND_CLASS_ZWAVEPLUS_INFO', 0x60: 'COMMAND_CLASS_MULTI_INSTANCE/CHANNEL', 0x61: 'COMMAND_CLASS_DISPLAY', 0x62: 'COMMAND_CLASS_DOOR_LOCK', @@ -1366,6 +1384,19 @@ Get the version of the Z-Wave API library used by a controller. cdef string c_string = self.manager.GetLibraryVersion(homeid) return cstr_to_str(c_string.c_str()) + def getPythonLibraryFlavor(self): + ''' +.. _getPythonLibraryFlavor: + +Get the flavor of the python library. + +:return: A string containing the python library flavor. For example, "embed". +:rtype: str +:see: getLibraryTypeName_, getLibraryVersion_, getOzwLibraryVersion_, getOzwLibraryLongVersion + + ''' + return "%s" % (PY_LIB_FLAVOR_STRING) + def getPythonLibraryVersion(self): ''' .. _getPythonLibraryVersion: @@ -1797,10 +1828,6 @@ Statistics: * averageResponseRTT #Average Reponse round trip time. * quality # Node quality measure * lastReceivedMessage[254] # Place to hold last received message - * ccData # List of statistic - * commandClassId # Num of commandClass id. - * sentCnt # Number of messages sent from this CommandClass. - * receivedCnt # Number of messages received from this CommandClass. :param homeId: The Home ID of the Z-Wave controller. :type homeId: int @@ -1833,16 +1860,6 @@ Statistics: ret['lastReceivedMessage'] = [] for i in range( 0, 254) : ret['lastReceivedMessage'] .append(data.m_lastReceivedMessage[i]) - listccdata =[] - while not data.m_ccData.empty() : - ccd = {} - temp = data.m_ccData.back() - ccd['commandClassId'] = temp.m_commandClassId - ccd['sentCnt'] = temp.m_sentCnt - ccd['receivedCnt'] = temp.m_receivedCnt - listccdata.append(ccd) - data.m_ccData.pop_back(); - ret['ccData'] = listccdata return ret def requestNodeDynamic(self, homeid, nodeid): diff --git a/src-lib/libopenzwave/node.pxd b/src-lib/libopenzwave/node.pxd index f8e076f1..9f99d72d 100755 --- a/src-lib/libopenzwave/node.pxd +++ b/src-lib/libopenzwave/node.pxd @@ -18,8 +18,6 @@ along with python-openzwave. If not, see http://www.gnu.org/licenses. """ from libc.stdint cimport uint32_t, int32_t, int16_t, uint8_t, int8_t -from libcpp.vector cimport vector -#from libcpp.string cimport string from mylibc cimport string cdef extern from "Node.h" namespace "OpenZWave::Node": @@ -46,15 +44,15 @@ cdef extern from "Node.h" namespace "OpenZWave::Node": uint32_t m_receivedCnt # Number of messages received from this node. uint32_t m_receivedDups # Number of duplicated messages received; uint32_t m_receivedUnsolicited # Number of messages received unsolicited + uint32_t m_lastRequestRTT # Last message request RTT + uint32_t m_lastResponseRTT # Last message response RTT string m_sentTS # Last message sent time string m_receivedTS # Last message received time - uint32_t m_lastRequestRTT # Last message request RTT uint32_t m_averageRequestRTT # Average Request Round Trip Time (ms). - uint32_t m_lastResponseRTT # Last message response RTT uint32_t m_averageResponseRTT #Average Reponse round trip time. uint8_t m_quality # Node quality measure uint8_t m_lastReceivedMessage[254] # Place to hold last received message - vector[CommandClassData] m_ccData # List of statistic on each command_class + uint8_t m_errors # Count errors for dead node detection ctypedef NodeData NodeData_t diff --git a/src-manager/pyozwman/ozwsh_widgets.py b/src-manager/pyozwman/ozwsh_widgets.py index 8b2725fc..9c892614 100755 --- a/src-manager/pyozwman/ozwsh_widgets.py +++ b/src-manager/pyozwman/ozwsh_widgets.py @@ -428,9 +428,11 @@ def read_lines(self): self.lines.append(urwid.Text( " %s:%s" % (groups[group].index,groups[group].label), align='left')) self.size += 1 for assoc in groups[group].associations: - self.lines.append(AssociationItem(assoc, \ - self.window.network.nodes[assoc].name - )) + if assoc in self.window.network.nodes: + aname = self.window.network.nodes[assoc].name + else: + aname = "[%d missing]" % (assoc) + self.lines.append(AssociationItem(assoc, aname)) self.size += 1 self._modified() @@ -478,7 +480,7 @@ def remove(self, param, value): self.window.status_bar.update(status="Invalid index or node ID %s/%s" % (param, value)) return False if param in self.window.network.nodes[self.node_id].groups: - if value in self.window.network.nodes[self.node_id].groups : + if value in self.window.network.nodes[self.node_id].groups[param].associations : self.window.network.nodes[self.node_id].groups[param].remove_association(value) self.window.status_bar.update(status='Group %s updated' % param) return True @@ -1340,7 +1342,7 @@ def add(self, param, value): def set(self, param, value): values = self.window.network.nodes[self.node_id].values try: - param = long(param) + param = int(param) except: ok = False for val in values: @@ -1373,7 +1375,7 @@ def set(self, param, value): def poll(self, param, value): values = self.window.network.nodes[self.node_id].values try: - param = long(param) + param = int(param) except: ok = False for val in values: @@ -1973,7 +1975,7 @@ def cd(self, directory): def delete(self, value): valueid = None try: - valueid = long(value) + valueid = int(value) except: ok = False try: diff --git a/src-python_openzwave/python_openzwave/scripts/__init__.py b/src-python_openzwave/python_openzwave/scripts/__init__.py new file mode 100755 index 00000000..240ad6d1 --- /dev/null +++ b/src-python_openzwave/python_openzwave/scripts/__init__.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +__license__ = """ + +This file is part of **python-openzwave** project https://github.com/OpenZWave/python-openzwave. + +License : GPL(v3) + +**python-openzwave** is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +**python-openzwave** is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +You should have received a copy of the GNU General Public License +along with python-openzwave. If not, see http://www.gnu.org/licenses. +""" +__copyright__ = "Copyright © 2012-2015 Sébastien GALLET aka bibi21000" +__author__ = 'Sébastien GALLET aka bibi21000' +__email__ = 'bibi21000@gmail.com' + +try: + __import__('pkg_resources').declare_namespace("openzwave") +except: + # bootstrapping + pass diff --git a/src-lib/scripts/pyozw_check b/src-python_openzwave/python_openzwave/scripts/pyozw_check.py similarity index 56% rename from src-lib/scripts/pyozw_check rename to src-python_openzwave/python_openzwave/scripts/pyozw_check.py index 003770db..0d888a2f 100644 --- a/src-lib/scripts/pyozw_check +++ b/src-python_openzwave/python_openzwave/scripts/pyozw_check.py @@ -32,6 +32,8 @@ args = None def imports(args): + if args.timeout is None: + args.timeout = 2 if args.output == 'txt': print("-------------------------------------------------------------------------------") print("Import libs") @@ -51,6 +53,8 @@ def imports(args): print("Try to get python_openzwave full version") print(manager.getPythonLibraryVersion()) print("Try to get openzwave version") + print(manager.getPythonLibraryVersion()) + print("Try to get openzwave version") print(manager.getOzwLibraryVersion()) print("Try to get default config path") print(libopenzwave.configPath()) @@ -61,7 +65,7 @@ def imports(args): time.sleep(0.5) print("Try to import openzwave (API)") import openzwave - + elif args.output == 'raw': import libopenzwave from libopenzwave import PyLogLevels @@ -92,19 +96,21 @@ def zwcallback(zwargs): if notify_type == "DriverReady": global home_id home_id = zwargs['homeId'] - + #~ print("Received {0} : {1}".format(notify_type,libopenzwave.PyNotifications[notify_type].doc)) if args.output == 'txt': print("Received {0}".format(notify_type)) def init_device(args): global home_id + if args.timeout is None: + args.timeout = 15 if args.output == 'txt': print("-------------------------------------------------------------------------------") print("Intialize device {0}".format(args.device)) import libopenzwave print("Try to get options") - options = libopenzwave.PyOptions(user_path=".", cmd_line="--logging true") + options = libopenzwave.PyOptions(config_path=args.config_path, user_path=args.user_path, cmd_line="--logging true") options.lock() time.sleep(1.0) print("Try to get manager") @@ -146,7 +152,7 @@ def init_device(args): print("{0:08x}".format(home_id)) elif args.output == 'raw': import libopenzwave - options = libopenzwave.PyOptions(user_path=".", cmd_line="--logging false") + options = libopenzwave.PyOptions(config_path=args.config_path, user_path=args.user_path, cmd_line="--logging false") options.lock() time.sleep(1.0) manager = libopenzwave.PyManager() @@ -171,14 +177,95 @@ def init_device(args): manager.destroy() time.sleep(0.2) options.destroy() - + +def list_nodes(args): + global home_id + if args.timeout is None: + args.timeout = 60*60*4+1 + import openzwave + from openzwave.node import ZWaveNode + from openzwave.value import ZWaveValue + from openzwave.scene import ZWaveScene + from openzwave.controller import ZWaveController + from openzwave.network import ZWaveNetwork + from openzwave.option import ZWaveOption + + #Define some manager options + print("-------------------------------------------------------------------------------") + print("Define options for device {0}".format(args.device)) + options = ZWaveOption(device=args.device, config_path=args.config_path, user_path=args.user_path) + options.set_log_file("OZW_Log.log") + options.set_append_log_file(False) + options.set_console_output(False) + options.set_save_log_level("Debug") + options.set_logging(True) + options.lock() + + print("Start network") + network = ZWaveNetwork(options, log=None) + + delta = 0.5 + for i in range(0, int(args.timeout/delta)): + time.sleep(delta) + if network.state >= network.STATE_AWAKED: + break + + print("-------------------------------------------------------------------------------") + print("Network is awaked. Talk to controller.") + print("Get python_openzwave version : {}".format(network.controller.python_library_version)) + print("Get python_openzwave config version : {}".format(network.controller.python_library_config_version)) + print("Get python_openzwave flavor : {}".format(network.controller.python_library_flavor)) + print("Get openzwave version : {}".format(network.controller.ozw_library_version)) + print("Get config path : {}".format(network.controller.library_config_path)) + print("Controller capabilities : {}".format(network.controller.capabilities)) + print("Controller node capabilities : {}".format(network.controller.node.capabilities)) + print("Nodes in network : {}".format(network.nodes_count)) + + print("-------------------------------------------------------------------------------") + if args.timeout > 1800: + print("You defined a really long timneout. Please use --help to change this feature.") + print("Wait for network ready ({0}s)".format(args.timeout)) + for i in range(0, int(args.timeout/delta)): + time.sleep(delta) + if network.state == network.STATE_READY: + break + print("-------------------------------------------------------------------------------") + if network.state == network.STATE_READY: + print("Network is ready. Get nodes") + elif network.state == network.STATE_AWAKED: + print("Network is awake. Some sleeping devices may miss. You can increase timeout to get them. But will continue.") + else: + print("Network is still starting. You MUST increase timeout. But will continue.") + + for node in network.nodes: + + print("------------------------------------------------------------") + print("{} - Name : {} ( Location : {} )".format(network.nodes[node].node_id, network.nodes[node].name, network.nodes[node].location)) + print(" {} - Ready : {} / Awake : {} / Failed : {}".format(network.nodes[node].node_id, network.nodes[node].is_ready, network.nodes[node].is_awake, network.nodes[node].is_failed)) + print(" {} - Manufacturer : {} ( id : {} )".format(network.nodes[node].node_id, network.nodes[node].manufacturer_name, network.nodes[node].manufacturer_id)) + print(" {} - Product : {} ( id : {} / type : {} / Version : {})".format(network.nodes[node].node_id, network.nodes[node].product_name, network.nodes[node].product_id, network.nodes[node].product_type, network.nodes[node].version)) + print(" {} - Command classes : {}".format(network.nodes[node].node_id, network.nodes[node].command_classes_as_string)) + print(" {} - Capabilities : {}".format(network.nodes[node].node_id, network.nodes[node].capabilities)) + print(" {} - Neighbors : {} / Power level : {}".format(network.nodes[node].node_id, network.nodes[node].neighbors, network.nodes[node].get_power_level())) + print(" {} - Is sleeping : {} / Can wake-up : {} / Battery level : {}".format(network.nodes[node].node_id, network.nodes[node].is_sleeping, network.nodes[node].can_wake_up(), network.nodes[node].get_battery_level())) + + print("------------------------------------------------------------") + print("Driver statistics : {}".format(network.controller.stats)) + print("------------------------------------------------------------") + print("Stop network") + network.stop() + print("Exit") + def pyozw_parser(): parser = argparse.ArgumentParser(description='Run python_openzwave basics checks.') parser.add_argument('-o', '--output', action='store', help='The format (txt, raw, ...)', choices=['txt', 'raw'], default='txt') - parser.add_argument('-d', '--device', action='store', help='The device port', default='/dev/ttyUSB0') + parser.add_argument('-d', '--device', action='store', help='The device port', default=None) parser.add_argument('-m', '--imports', action='store_true', help='Import all libs', default=True) parser.add_argument('-i', '--init_device', action='store_true', help='Intialize the device', default=False) - parser.add_argument('-t', '--timeout', action='store',type=int, help='The default timeout for zwave network sniffing', default=10) + parser.add_argument('-l', '--list_nodes', action='store_true', help='List the nodes on zwave network', default=False) + parser.add_argument('-t', '--timeout', action='store',type=int, help='The default timeout for zwave network sniffing', default=None) + parser.add_argument('--config_path', action='store', help='The config_path for openzwave', default=None) + parser.add_argument('--user_path', action='store', help='The user_path for openzwave', default=".") return parser def main(): @@ -187,8 +274,11 @@ def main(): args = parser.parse_args() if args.init_device: init_device(args) + elif args.list_nodes: + list_nodes(args) elif args.imports: imports(args) + if __name__ == '__main__': main() diff --git a/src-manager/scripts/pyozw_shell b/src-python_openzwave/python_openzwave/scripts/pyozw_shell.py similarity index 98% rename from src-manager/scripts/pyozw_shell rename to src-python_openzwave/python_openzwave/scripts/pyozw_shell.py index fd365333..b6b67fb7 100755 --- a/src-manager/scripts/pyozw_shell +++ b/src-python_openzwave/python_openzwave/scripts/pyozw_shell.py @@ -49,7 +49,7 @@ def main(): '-d', '--device', dest='device', type="str", - default="/dev/ttyUSB0", + default=None, help="The path to your ZWave device") parser.add_option( diff --git a/tests/api/common.py b/tests/api/common.py index 18a74dff..b771cf64 100644 --- a/tests/api/common.py +++ b/tests/api/common.py @@ -30,7 +30,6 @@ import unittest import threading import logging -import json as mjson import shutil from nose.plugins.skip import SkipTest import libopenzwave @@ -51,7 +50,7 @@ from louie import dispatcher from tests.common import SLEEP -from tests.common import TestPyZWave +from tests.common import TestPyZWave, json_dumps, json_loads class TestApi(TestPyZWave): """ @@ -68,7 +67,6 @@ def setUpClass(self): self.options.set_save_log_level(self.ozwlog) self.options.set_logging(True) self.options.lock() - dispatcher.connect(self.node_update, ZWaveNetwork.SIGNAL_NODE) self.network = ZWaveNetwork(self.options) self.node_result = None self.ctrl_command_result = None @@ -86,11 +84,12 @@ def tearDownClass(self): self.network = None def setUp(self): + dispatcher.connect(self.node_update, ZWaveNetwork.SIGNAL_NODE) self.node_result = None self.ctrl_command_result = None self.ctrl_command_signal = None self.wait_for_network_state(self.network.STATE_AWAKED, 1) - time.sleep(1.0) + time.sleep(2.0) self.wait_for_queue() self.active_nodes = {} for node in self.network.nodes: @@ -98,6 +97,9 @@ def setUp(self): self.active_nodes[node] = self.network.nodes[node] print('active nodes : %s' % self.active_nodes) + def tearDown(self): + dispatcher.disconnect(self.node_update, ZWaveNetwork.SIGNAL_NODE) + def wait_for_queue(self): for i in range(0,60): if self.network.controller.send_queue_count <= 0: diff --git a/tests/api/test_command.py b/tests/api/test_command.py index 609187c8..264fe0d3 100644 --- a/tests/api/test_command.py +++ b/tests/api/test_command.py @@ -62,7 +62,8 @@ def test_010_battery_item(self): for node in self.active_nodes: for val in self.active_nodes[node].get_battery_levels() : ran = True - self.assertTrue(isinstance(self.active_nodes[node].get_battery_level(val), integer_types)) + self.assertTrue(isinstance(self.active_nodes[node].get_battery_level(val), + six.integer_types)) if ran == False : self.skipTest("No battery found") diff --git a/tests/api/test_controller.py b/tests/api/test_controller.py index d75ae96f..5254c2a3 100644 --- a/tests/api/test_controller.py +++ b/tests/api/test_controller.py @@ -59,6 +59,7 @@ def test_010_controller(self): self.assertTrue(isinstance(self.network.controller.name, string_types)) self.assertTrue(isinstance(self.network.controller.ozw_library_version, string_types)) self.assertTrue(isinstance(self.network.controller.python_library_version, string_types)) + self.assertTrue(isinstance(self.network.controller.python_library_flavor, string_types)) self.assertTrue(isinstance(self.network.controller.library_description, string_types)) def test_020_controller_capabilities(self): @@ -71,6 +72,17 @@ def test_030_controller_send_queue(self): def test_040_controller_stats(self): self.assertEqual(type(self.network.controller.stats), type(dict())) + def test_050_controller_update_ozw_config(self): + #Remove old config version + try: + os.remove(os.path.join(self.network.controller.library_config_path, 'pyozw_config.version')) + except: + pass + self.assertTrue(self.network.controller.python_library_config_version.startswith('Original')) + if not ( self.network.controller.python_library_flavor in ['shared']): + self.network.controller.update_ozw_config() + self.assertTrue(self.network.controller.python_library_config_version.startswith('Git')) + def test_110_controller_soft_reset(self): time.sleep(5) self.network.controller.soft_reset() diff --git a/tests/api/test_controller_command.py b/tests/api/test_controller_command.py index 047fca19..0e5c3b51 100644 --- a/tests/api/test_controller_command.py +++ b/tests/api/test_controller_command.py @@ -64,9 +64,10 @@ def tearDownClass(self): super(TestControllerCommand, self).tearDownClass() def setUp(self): - self.wait_for_network_state(self.network.STATE_READY, 1) - self.wait_for_queue() - self.ctrl_state_result = None + # ~ self.wait_for_network_state(self.network.STATE_READY, 1) + # ~ self.wait_for_queue() + # ~ self.ctrl_state_result = None + TestApi.setUp(self) dispatcher.connect(self.ctrl_message, ZWaveNetwork.SIGNAL_CONTROLLER_COMMAND) dispatcher.connect(self.ctrl_waiting, ZWaveNetwork.SIGNAL_CONTROLLER_WAITING) time.sleep(2.0) @@ -106,9 +107,10 @@ def test_005_request_controller_status(self): def test_010_command_send_node_information_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: - node_id = max(self.network.nodes.keys()) + # ~ node_id = max(self.network.nodes.keys()) + # ~ node_id = self.active_nodes.keys()[1] ret = self.network.controller.send_node_information(node_id) self.assertTrue(ret) current = None @@ -120,7 +122,9 @@ def test_010_command_send_node_information_nodes(self): break else: time.sleep(1.0) + print(self.ctrl_command_signal) self.assertEqual(current, self.network.controller.STATE_COMPLETED) + self.assertEqual(self.ctrl_command_signal['node_id'], node_id) def test_015_command_send_node_information_controller(self): self.ctrl_state_result = None @@ -140,7 +144,8 @@ def test_015_command_send_node_information_controller(self): def test_020_command_request_node_neighbor_update_nodes(self): self.wipTest() self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: ret = self.network.controller.request_node_neighbor_update(node_id) self.assertTrue(ret) @@ -173,7 +178,7 @@ def test_025_command_request_node_neighbor_update_controller(self): def test_030_command_request_network_update_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.request_network_update(node_id) @@ -206,7 +211,7 @@ def test_035_command_request_network_update_controller(self): def test_040_command_delete_all_return_routes_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.delete_all_return_routes(node_id) @@ -239,7 +244,7 @@ def test_045_command_delete_all_return_routes_controller(self): def test_050_command_assign_return_route_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.assign_return_route(node_id) @@ -272,7 +277,7 @@ def test_055_command_assign_return_route_controller(self): def test_060_command_has_node_failed_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.has_node_failed(node_id) @@ -287,10 +292,11 @@ def test_060_command_has_node_failed_nodes(self): else: time.sleep(1.0) self.assertEqual(current, self.network.controller.STATE_NODEOK) + self.assertEqual(self.ctrl_command_signal['node_id'], node_id) def test_070_command_remove_failed_node_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.remove_failed_node(node_id) @@ -308,7 +314,7 @@ def test_070_command_remove_failed_node_nodes(self): def test_080_command_replace_failed_node_nodes(self): self.ctrl_state_result = None - node_ids = [ k for k in self.network.nodes.keys() if k != self.network.controller.node_id ] + node_ids = [ k for k in self.active_nodes.keys() if k != self.network.controller.node_id ] for node_id in node_ids: node_id = max(self.network.nodes.keys()) ret = self.network.controller.replace_failed_node(node_id) diff --git a/tests/api/test_network.py b/tests/api/test_network.py index b0ed1806..17db3cd4 100644 --- a/tests/api/test_network.py +++ b/tests/api/test_network.py @@ -34,7 +34,6 @@ import random import socket import re -import json import six if six.PY3: from pydispatch import dispatcher @@ -52,7 +51,7 @@ from tests.common import pyozw_version from tests.common import SLEEP from tests.api.common import TestApi -from tests.common import TestPyZWave +from tests.common import TestPyZWave, json_dumps, json_loads class TestNetwork(TestApi): @@ -82,14 +81,14 @@ def test_120_network_poll(self): def test_200_network_to_dict(self): dnetwork = self.network.to_dict() self.assertEqual(type(dnetwork), type(dict())) - res = json.dumps(dnetwork) + res = json_dumps(dnetwork) self.assertNotEqual(res, None) self.assertTrue(len(res)>0) def test_220_network_nodes_to_dict(self): dnodes = self.network.nodes_to_dict() self.assertEqual(type(dnodes), type(dict())) - res = json.dumps(dnodes) + res = json_dumps(dnodes) self.assertNotEqual(res, None) self.assertTrue(len(res)>0) diff --git a/tests/api/test_node.py b/tests/api/test_node.py index 3972dad7..9bd33f73 100644 --- a/tests/api/test_node.py +++ b/tests/api/test_node.py @@ -60,14 +60,19 @@ def test_020_node_capabilities(self): node_id = max(self.network.nodes.keys()) self.assertEqual(type(self.network.nodes[node_id].capabilities), type(set())) + def test_030_node_statistics(self): + node_id = max(self.network.nodes.keys()) + self.assertEqual(type(self.network.nodes[node_id].stats), type(dict())) + def test_310_node(self): node_id = max(self.network.nodes.keys()) self.assertTrue(isinstance(self.network.nodes[node_id].node_id, integer_types)) self.assertTrue(self.network.nodes[node_id].node_id > 0) def test_330_node_neighbors(self): - node_id = max(self.network.nodes.keys()) - self.assertEqual(type(self.network.nodes[node_id].neighbors), type(set())) + #~ node_id = max(self.network.nodes.keys()) + for node_id in self.active_nodes: + self.assertEqual(type(self.network.nodes[node_id].neighbors), type(set())) def test_340_node_baud_rate(self): node_id = max(self.network.nodes.keys()) diff --git a/tests/api/test_nodes.py b/tests/api/test_nodes.py index 74922da0..9fe5baa1 100644 --- a/tests/api/test_nodes.py +++ b/tests/api/test_nodes.py @@ -34,7 +34,6 @@ import random import socket import re -import json import six if six.PY3: from pydispatch import dispatcher @@ -52,7 +51,7 @@ from tests.common import pyozw_version from tests.common import SLEEP from tests.api.common import TestApi -from tests.common import TestPyZWave +from tests.common import TestPyZWave, json_dumps, json_loads class TestNodes(TestApi): @@ -79,7 +78,7 @@ def test_200_nodes_to_dict(self): self.assertTrue('groups' in noded) self.assertTrue('neighbors' in noded) self.assertTrue('capabilities' in noded) - res = json.dumps(noded) + res = json_dumps(noded) except TypeError: res = None self.assertNotEqual(res, None) @@ -88,7 +87,7 @@ def test_210_controller_to_dict(self): try : nodes = self.network.controller.to_dict() self.assertEqual(type(nodes), type(dict())) - res = json.dumps(nodes) + res = json_dumps(nodes) except TypeError: res = None self.assertNotEqual(res, None) @@ -99,7 +98,7 @@ def test_220_nodes_groups_to_dict(self): groups = self.active_nodes[node].groups_to_dict() self.assertTrue(type(groups), type(dict())) self.assertEqual(type(groups), type(dict())) - res = json.dumps(groups) + res = json_dumps(groups) except TypeError: res = None self.assertNotEqual(res, None) diff --git a/tests/api/test_scene.py b/tests/api/test_scene.py index 45143f06..22f3229e 100644 --- a/tests/api/test_scene.py +++ b/tests/api/test_scene.py @@ -50,8 +50,7 @@ from tests.common import pyozw_version from tests.common import SLEEP from tests.api.common import TestApi -from tests.common import TestPyZWave -import json +from tests.common import TestPyZWave, json_dumps, json_loads class TestScene(TestApi): count = 0 @@ -83,7 +82,7 @@ def test_005_scene_add_remove(self): def test_010_scenes_to_dict(self): dscenes = self.network.scenes_to_dict() self.assertEqual(type(dscenes), type(dict())) - res = json.dumps(dscenes) + res = json_dumps(dscenes) self.assertNotEqual(res, None) self.assertTrue(len(res)>0) @@ -93,7 +92,7 @@ def test_020_scene_to_dict(self): try : scene = scenes[scene].to_dict() self.assertEqual(type(scene), type(dict())) - res = json.dumps(scene) + res = json_dumps(scene) except TypeError: res = None self.assertNotEqual(res, None) diff --git a/tests/api/test_switch.py b/tests/api/test_switch.py index 5b277fe7..697bfff4 100644 --- a/tests/api/test_switch.py +++ b/tests/api/test_switch.py @@ -26,7 +26,9 @@ """ -import os, shutil +import os +import shutil +import sys import time import unittest from pprint import pprint diff --git a/tests/api/test_value.py b/tests/api/test_value.py index a42be651..77c23192 100644 --- a/tests/api/test_value.py +++ b/tests/api/test_value.py @@ -53,8 +53,7 @@ from tests.common import pyozw_version from tests.common import SLEEP from tests.api.common import TestApi -from tests.common import TestPyZWave -import json +from tests.common import TestPyZWave, json_dumps, json_loads class TestValue(TestApi): @@ -64,16 +63,13 @@ def test_200_values_to_dict(self): val = self.active_nodes[node].values[value].to_dict() print(val) self.assertEqual(type(val), type(dict())) - self.assertTrue('data_item' in val) + self.assertTrue('data_items' in val) self.assertTrue('command_class' in val) self.assertTrue('is_read_only' in val) self.assertTrue('is_write_only' in val) self.assertTrue('type' in val) self.assertTrue('index' in val) - try : - res = json.dumps(val) - except TypeError: - res = None + res = json_dumps(val) self.assertNotEqual(res, None) def test_210_values_check_data(self): diff --git a/tests/common.py b/tests/common.py index 03c12ff7..badec123 100644 --- a/tests/common.py +++ b/tests/common.py @@ -25,19 +25,36 @@ """ -#The common sleep dealy to wait for network -#We wait 1*SLEEP for network.STATE_AWAKED -#After that we wait 1*SLEEP for network.STATE_READY -SLEEP = 45 - -import sys, os +import os +import shutil +import sys import time import unittest import threading import logging -import json as mjson +import json +#~ import bson import six +#The common sleep dealy to wait for network +#We wait 1*SLEEP for network.STATE_AWAKED +#After that we wait 1*SLEEP for network.STATE_READY +SLEEP = 45 + +class SetEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, set): + return list(obj) + return json.JSONEncoder.default(self, obj) + +def json_dumps(data_as_object): + #~ return json.dumps(data_as_object, default=json_util.default) + return json.dumps(data_as_object, cls=SetEncoder) + +def json_loads(data_as_string): + #~ return json.loads(data_as_string, object_hook=json_util.object_hook) + return json.loads(data_as_string) + from nose.plugins.skip import SkipTest sys.path.insert(1, os.path.abspath('..')) @@ -50,7 +67,7 @@ class TestPyZWave(unittest.TestCase): """ device = "/dev/ttyUSB0" ozwlog = "Debug" - ozwout = False + ozwout = True pylog = logging.DEBUG userpath = ".tests_user_path" @@ -75,6 +92,7 @@ def setUpClass(self): except: pass + @classmethod def skipTest(self, message): """Skip a test """ diff --git a/tests/lib/autobuild/test_lib.py b/tests/lib/autobuild/test_lib.py index 0436a4c5..e7e05eae 100644 --- a/tests/lib/autobuild/test_lib.py +++ b/tests/lib/autobuild/test_lib.py @@ -56,8 +56,14 @@ def test_010_options_exceptions(self): shutil.rmtree(self.userpath) except: pass - os.makedirs(self.userpath) - os.makedirs(fake_config_dir) + try: + os.makedirs(self.userpath) + except: + pass + try: + os.makedirs(fake_config_dir) + except: + pass os.chmod(fake_config_dir, stat.S_IREAD|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) with self.assertRaises(libopenzwave.LibZWaveException): options = libopenzwave.PyOptions(config_path=fake_config_dir, user_path=None, cmd_line=None) @@ -66,8 +72,14 @@ def test_010_options_exceptions(self): shutil.rmtree(self.userpath) except: pass - os.makedirs(self.userpath) - os.makedirs(fake_config_dir) + try: + os.makedirs(self.userpath) + except: + pass + try: + os.makedirs(fake_config_dir) + except: + pass os.chmod(fake_config_dir, stat.S_IREAD|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH|stat.S_IWRITE|stat.S_IWUSR|stat.S_IWGRP|stat.S_IWOTH) with self.assertRaises(libopenzwave.LibZWaveException): options = libopenzwave.PyOptions(config_path=fake_config_dir, user_path=None, cmd_line=None) diff --git a/tests/lib/common.py b/tests/lib/common.py index d5277d4c..2f10f621 100644 --- a/tests/lib/common.py +++ b/tests/lib/common.py @@ -30,7 +30,6 @@ import unittest import threading import logging -import json as mjson import shutil from nose.plugins.skip import SkipTest @@ -115,7 +114,6 @@ def tearDownClass(self): super(TestPyZWave, self).tearDownClass() def start_lib(self): - if self.options is None: self.options = libopenzwave.PyOptions(config_path="openzwave/config", \ user_path=self.userpath, cmd_line="--logging false") @@ -142,15 +140,19 @@ def start_lib(self): @classmethod def stop_lib(self): if self.manager is not None: + print("Remove driver") self.manager.removeDriver(self.device) - time.sleep(1.0) + time.sleep(2.0) + print("Remove watcher") self.manager.removeWatcher(self.zwcallback) - time.sleep(1.0) + time.sleep(2.0) + print("Destroy manager") self.manager.destroy() time.sleep(1.0) self.manager = None if self.options is not None: self.options.destroy() + print("Destroy options") time.sleep(1.0) self.options = None self.homeid = None @@ -238,11 +240,12 @@ def zwcallback(self, args): print('Error in manager callback : %s' % traceback.format_exception(*sys.exc_info())) def wait_for_ready(self): - for i in range(0,15): + for i in range(0,20): if self.ready == True: break else: time.sleep(1.0) + print("Network ready : %s"%self.ready) def wait_for_queue(self): for i in range(0,60): diff --git a/tests/lib/test_driver.py b/tests/lib/test_driver.py index c3e2de74..087033cd 100644 --- a/tests/lib/test_driver.py +++ b/tests/lib/test_driver.py @@ -34,7 +34,7 @@ import random import socket import libopenzwave -from common import TestLib +from .common import TestLib import re from tests.common import pyozw_version from six import string_types @@ -55,9 +55,6 @@ def setUp(self): user_path=self.userpath, cmd_line="--logging false") self.options.lock() - def tearDown(self): - self.stop_lib() - def test_100_start(self): time.sleep(1.0) self.manager = libopenzwave.PyManager() diff --git a/tests/lib/test_node.py b/tests/lib/test_node.py index df93cebd..b7b504fc 100644 --- a/tests/lib/test_node.py +++ b/tests/lib/test_node.py @@ -33,7 +33,7 @@ import datetime import random import socket -from common import TestLib +from .common import TestLib import re from tests.common import pyozw_version from six import string_types @@ -50,10 +50,11 @@ def emit(self, record): class TestNode(TestLib): - - def test_100_controller_name(self): + def setUp(self): self.start_lib() self.wait_for_ready() + + def skip_100_controller_name(self): oldname = self.manager.getNodeName(self.homeid, 1) self.assertTrue(isinstance(oldname, string_types)) self.manager.setNodeName(self.homeid, 1, "test lib name") @@ -61,8 +62,6 @@ def test_100_controller_name(self): self.assertTrue(isinstance(newname, string_types)) def test_101_controller_name_accent(self): - self.start_lib() - self.wait_for_ready() oldname = self.manager.getNodeName(self.homeid, 1) self.assertTrue(isinstance(oldname, string_types)) self.manager.setNodeName(self.homeid, 1, "test lib name éé") diff --git a/tests/manager/autobuild/test_manager.py b/tests/manager/autobuild/test_manager.py index e81e1185..d8568016 100644 --- a/tests/manager/autobuild/test_manager.py +++ b/tests/manager/autobuild/test_manager.py @@ -32,7 +32,7 @@ import sys import time import logging -import json as mjson +import unittest from tests.manager.common import TestManager diff --git a/tests/manager/common.py b/tests/manager/common.py index 89356f06..926cee57 100644 --- a/tests/manager/common.py +++ b/tests/manager/common.py @@ -29,7 +29,6 @@ import sys, os import time import logging -import json as mjson from tests.common import SLEEP from tests.common import TestPyZWave diff --git a/tests/web/autobuild/test_web.py b/tests/web/autobuild/test_web.py index ddfa4f8d..52488258 100644 --- a/tests/web/autobuild/test_web.py +++ b/tests/web/autobuild/test_web.py @@ -32,16 +32,16 @@ import sys import time import logging -import json as mjson +import unittest -from tests.web.common import FlaskTestBase +#~ from tests.web.common import FlaskTestBase -class FlaskTest(FlaskTestBase): +#~ class FlaskTest(FlaskTestBase): - def test_000_import_listener(self): - self.skipPython3() - from pyozwweb.app.listener import ListenerThread, start_listener, stop_listener - from pyozwweb.app import run_app, create_app + #~ def test_000_import_listener(self): + #~ self.skipPython3() + #~ from pyozwweb.app.listener import ListenerThread, start_listener, stop_listener + #~ from pyozwweb.app import run_app, create_app if __name__ == '__main__': sys.argv.append('-v') diff --git a/tests/web/common.py b/tests/web/common.py index 655f54bd..bb869546 100644 --- a/tests/web/common.py +++ b/tests/web/common.py @@ -29,7 +29,6 @@ import sys, os import time import logging -import json as mjson from flask import Flask diff --git a/tests/web/test_server.py b/tests/web/test_server.py index 1ada13f4..b5833cfe 100644 --- a/tests/web/test_server.py +++ b/tests/web/test_server.py @@ -32,49 +32,49 @@ import sys import time import logging -import json as mjson +import unittest -from flask.ext.socketio import SocketIO, emit, join_room, leave_room, close_room, disconnect -from flask.ext.socketio.test_client import SocketIOTestClient -from tests.web.common import FlaskTestCase +#~ from flask.ext.socketio import SocketIO, emit, join_room, leave_room, close_room, disconnect +#~ from flask.ext.socketio.test_client import SocketIOTestClient +#~ from tests.web.common import FlaskTestCase -class FlaskServerTest(FlaskTestCase): +#~ class FlaskServerTest(FlaskTestCase): - def test_000_server_start(self): - rv = self.client.get('/') - self.assertTrue('Welcome to PyOzwWeb' in rv.data) + #~ def test_000_server_start(self): + #~ rv = self.client.get('/') + #~ self.assertTrue('Welcome to PyOzwWeb' in rv.data) - def test_001_error_404(self): - rv = self.client.get('/bad_page') - self.assertEqual(rv.status,'404 NOT FOUND') + #~ def test_001_error_404(self): + #~ rv = self.client.get('/bad_page') + #~ self.assertEqual(rv.status,'404 NOT FOUND') - def test_100_home_is_up(self): - rv = self.client.get('/') - self.assertEqual(rv.status,'200 OK') + #~ def test_100_home_is_up(self): + #~ rv = self.client.get('/') + #~ self.assertEqual(rv.status,'200 OK') - def test_200_controller_is_up(self): - rv = self.client.get('/controller') - self.assertEqual(rv.status,'200 OK') + #~ def test_200_controller_is_up(self): + #~ rv = self.client.get('/controller') + #~ self.assertEqual(rv.status,'200 OK') - def test_300_values_is_up(self): - rv = self.client.get('/values') - self.assertEqual(rv.status,'200 OK') + #~ def test_300_values_is_up(self): + #~ rv = self.client.get('/values') + #~ self.assertEqual(rv.status,'200 OK') - def test_400_controller_is_up(self): - rv = self.client.get('/debug') - self.assertEqual(rv.status,'200 OK') + #~ def test_400_controller_is_up(self): + #~ rv = self.client.get('/debug') + #~ self.assertEqual(rv.status,'200 OK') - def test_500_node_is_up(self): - rv = self.client.get('/node/1') - self.assertEqual(rv.status,'200 OK') + #~ def test_500_node_is_up(self): + #~ rv = self.client.get('/node/1') + #~ self.assertEqual(rv.status,'200 OK') - def test_600_map_is_up(self): - rv = self.client.get('/map') - self.assertEqual(rv.status,'200 OK') + #~ def test_600_map_is_up(self): + #~ rv = self.client.get('/map') + #~ self.assertEqual(rv.status,'200 OK') - def test_700_scenes_is_up(self): - rv = self.client.get('/scenes') - self.assertEqual(rv.status,'200 OK') + #~ def test_700_scenes_is_up(self): + #~ rv = self.client.get('/scenes') + #~ self.assertEqual(rv.status,'200 OK') #def test_500_socketio_home(self): # rv = self.app.get('/socketio/')