What does the “n” mean for pins like “nRST”?

The n in pins names like nRST means not.

  • A pin named without n, for example RST or RESET, will perform its function (e.g. reset the device) when it is connected to VCC
  • A pin named with n, for example nRST or nRESET, will perform its function (e.g. reset the device) when it is connected to GND

nRESET has exactly the same meaning as overlining the name. For example \overline{\text{RESET}}. Some manufacturers prefer to use n instead of \overline{\text{RESET}} or ~RESET

Posted by Uli Köhler in Electronics

SN74LV245A as level shifter: How to use the ~OE pin

The ~OE pin on the SN74LV245A defines whether to enable the outputs on the chip. Which pins are inputs and which are outputs is defined by the DIR pins, see SN74LV245A as level shifter: How to use DIR pin for more information.

  • If ~OE is low (i.e. connected to GND), all output pins are enabled
  • If ~OE is high (i.e. connected to Vcc), all output pins are disabled

Note that there is no way to disable individual output pins for the SN74LV245A. You can only enable or disable all the pins together.

In most applications as a level shifter, you want to always enable the output: In order to do that, connect the ~OE pin to GND.

Posted by Uli Köhler in Electronics, Embedded

SN74LV245A as level shifter: How to use the DIR pin

The DIR pin on the SN74LV245A defines whether the A pins or the B pins are the input pins.

  • If DIR is low (i.e. connected to GND), all B pins are inputs and all A pins are outputs.
  • If DIR is high (i.e. connected to Vcc), all A pins are inputs and all B pins are outputs.
Posted by Uli Köhler in Electronics, Embedded

How to fix PlatformIO pio remote agent start: fatal error: ffi.h: No such file or directory

Problem:

Go to solution

When running pio remote agent start, during the package installation process, you see an error log like

ERROR: Command errored out with exit status 1:
 command: /home/pi/.platformio/penv/bin/python /tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-z_7hwbt9/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple --extra-index-url https://www.piwheels.org/simple -- 'setuptools>=40.6.0' wheel 'cffi>=1.12; platform_python_implementation != '"'"'PyPy'"'"'' 'setuptools-rust>=0.11.4'
     cwd: None
Complete output (284 lines):
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple, https://www.piwheels.org/simple
Collecting setuptools>=40.6.0
  Using cached setuptools-59.3.0.tar.gz (2.3 MB)
  Getting requirements to build wheel: started
  Getting requirements to build wheel: finished with status 'done'
  Installing backend dependencies: started
  Installing backend dependencies: finished with status 'done'
  Preparing metadata (pyproject.toml): started
  Preparing metadata (pyproject.toml): finished with status 'done'
Collecting wheel
  Using cached wheel-0.37.0.tar.gz (65 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Collecting cffi>=1.12
  Using cached cffi-1.15.0.tar.gz (484 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Collecting setuptools-rust>=0.11.4
  Using cached setuptools-rust-1.0.0.tar.gz (279 kB)
  Installing build dependencies: started
  Installing build dependencies: still running...
  Installing build dependencies: still running...
  Installing build dependencies: still running...
  Installing build dependencies: still running...
  Installing build dependencies: still running...
  Installing build dependencies: finished with status 'done'
  Getting requirements to build wheel: started
  Getting requirements to build wheel: finished with status 'done'
  Installing backend dependencies: started
  Installing backend dependencies: finished with status 'done'
  Preparing metadata (pyproject.toml): started
  Preparing metadata (pyproject.toml): finished with status 'done'
Collecting pycparser
  Using cached pycparser-2.21.tar.gz (170 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Collecting tomli>=1.2.1
  Using cached tomli-1.2.2.tar.gz (15 kB)
  Installing build dependencies: started
  Installing build dependencies: finished with status 'error'
  ERROR: Command errored out with exit status 2:
   command: /home/pi/.platformio/penv/bin/python /tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-e79tjyp1/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple --extra-index-url https://www.piwheels.org/simple --extra-index-url https://www.piwheels.org/simple -- 'flit_core>=3.2.0,<4'
       cwd: None
  Complete output (60 lines):
  Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple, https://www.piwheels.org/simple, https://www.piwheels.org/simple
  Collecting flit_core<4,>=3.2.0
    Using cached flit_core-3.5.1.tar.gz (27 kB)
    Getting requirements to build wheel: started
    Getting requirements to build wheel: finished with status 'done'
    Preparing metadata (pyproject.toml): started
    Preparing metadata (pyproject.toml): finished with status 'done'
  Collecting tomli
    Using cached tomli-1.2.2.tar.gz (15 kB)
  ERROR: Exception:
  Traceback (most recent call last):
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/cli/base_command.py", line 164, in exc_logging_wrapper
      status = run_func(*args)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/cli/req_command.py", line 205, in wrapper
      return func(self, options, args)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/commands/install.py", line 338, in run
      requirement_set = resolver.resolve(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/resolver.py", line 92, in resolve
      result = self._result = resolver.resolve(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 482, in resolve
      state = resolution.resolve(requirements, max_rounds=max_rounds)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 374, in resolve
      failure_causes = self._attempt_to_pin_criterion(name)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 214, in _attempt_to_pin_criterion
      criteria = self._get_updated_criteria(candidate)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 205, in _get_updated_criteria
      self._add_to_criteria(criteria, requirement, parent=candidate)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 173, in _add_to_criteria
      if not criterion.candidates:
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/structs.py", line 151, in __bool__
      return bool(self._sequence)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/found_candidates.py", line 155, in __bool__
      return any(self)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/found_candidates.py", line 143, in <genexpr>
      return (c for c in iterator if id(c) not in self._incompatible_ids)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/found_candidates.py", line 47, in _iter_built
      candidate = func()
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/factory.py", line 201, in _make_candidate_from_link
      self._link_candidate_cache[link] = LinkCandidate(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 281, in __init__
      super().__init__(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 156, in __init__
      self.dist = self._prepare()
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 225, in _prepare
      dist = self._prepare_distribution()
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 292, in _prepare_distribution
      return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/operations/prepare.py", line 482, in prepare_linked_requirement
      return self._prepare_linked_requirement(req, parallel_builds)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/operations/prepare.py", line 546, in _prepare_linked_requirement
      dist = _get_prepared_distribution(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/operations/prepare.py", line 57, in _get_prepared_distribution
      with req_tracker.track(req):
    File "/usr/lib/python3.9/contextlib.py", line 117, in __enter__
      return next(self.gen)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/req/req_tracker.py", line 122, in track
      self.add(req)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/req/req_tracker.py", line 92, in add
      raise LookupError(message)
  LookupError: https://files.pythonhosted.org/packages/aa/5b/62165da80cbc6e1779f342234c7ddc6c6bc9e64cef149046a9c0456f912b/tomli-1.2.2.tar.gz#sha256=c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee (from https://pypi.org/simple/tomli/) (requires-python:>=3.6) is already being built: tomli>=1.2.1 from https://files.pythonhosted.org/packages/aa/5b/62165da80cbc6e1779f342234c7ddc6c6bc9e64cef149046a9c0456f912b/tomli-1.2.2.tar.gz#sha256=c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee (from setuptools-rust>=0.11.4)
  ----------------------------------------
WARNING: Discarding https://files.pythonhosted.org/packages/aa/5b/62165da80cbc6e1779f342234c7ddc6c6bc9e64cef149046a9c0456f912b/tomli-1.2.2.tar.gz#sha256=c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee (from https://pypi.org/simple/tomli/) (requires-python:>=3.6). Command errored out with exit status 2: /home/pi/.platformio/penv/bin/python /tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-e79tjyp1/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple --extra-index-url https://www.piwheels.org/simple --extra-index-url https://www.piwheels.org/simple -- 'flit_core>=3.2.0,<4' Check the logs for full command output.
  Using cached tomli-1.2.1.tar.gz (14 kB)
  Installing build dependencies: started
  Installing build dependencies: finished with status 'error'
  ERROR: Command errored out with exit status 2:
   command: /home/pi/.platformio/penv/bin/python /tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-zwmgu3x5/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple --extra-index-url https://www.piwheels.org/simple --extra-index-url https://www.piwheels.org/simple -- 'flit_core>=3.2.0,<4'
       cwd: None
  Complete output (60 lines):
  Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple, https://www.piwheels.org/simple, https://www.piwheels.org/simple
  Collecting flit_core<4,>=3.2.0
    Using cached flit_core-3.5.1.tar.gz (27 kB)
    Getting requirements to build wheel: started
    Getting requirements to build wheel: finished with status 'done'
    Preparing metadata (pyproject.toml): started
    Preparing metadata (pyproject.toml): finished with status 'done'
  Collecting tomli
    Using cached tomli-1.2.2.tar.gz (15 kB)
  ERROR: Exception:
  Traceback (most recent call last):
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/cli/base_command.py", line 164, in exc_logging_wrapper
      status = run_func(*args)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/cli/req_command.py", line 205, in wrapper
      return func(self, options, args)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/commands/install.py", line 338, in run
      requirement_set = resolver.resolve(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/resolver.py", line 92, in resolve
      result = self._result = resolver.resolve(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 482, in resolve
      state = resolution.resolve(requirements, max_rounds=max_rounds)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 374, in resolve
      failure_causes = self._attempt_to_pin_criterion(name)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 214, in _attempt_to_pin_criterion
      criteria = self._get_updated_criteria(candidate)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 205, in _get_updated_criteria
      self._add_to_criteria(criteria, requirement, parent=candidate)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/resolvers.py", line 173, in _add_to_criteria
      if not criterion.candidates:
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_vendor/resolvelib/structs.py", line 151, in __bool__
      return bool(self._sequence)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/found_candidates.py", line 155, in __bool__
      return any(self)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/found_candidates.py", line 143, in <genexpr>
      return (c for c in iterator if id(c) not in self._incompatible_ids)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/found_candidates.py", line 47, in _iter_built
      candidate = func()
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/factory.py", line 201, in _make_candidate_from_link
      self._link_candidate_cache[link] = LinkCandidate(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 281, in __init__
      super().__init__(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 156, in __init__
      self.dist = self._prepare()
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 225, in _prepare
      dist = self._prepare_distribution()
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/resolution/resolvelib/candidates.py", line 292, in _prepare_distribution
      return preparer.prepare_linked_requirement(self._ireq, parallel_builds=True)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/operations/prepare.py", line 482, in prepare_linked_requirement
      return self._prepare_linked_requirement(req, parallel_builds)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/operations/prepare.py", line 546, in _prepare_linked_requirement
      dist = _get_prepared_distribution(
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/operations/prepare.py", line 57, in _get_prepared_distribution
      with req_tracker.track(req):
    File "/usr/lib/python3.9/contextlib.py", line 117, in __enter__
      return next(self.gen)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/req/req_tracker.py", line 122, in track
      self.add(req)
    File "/tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip/_internal/req/req_tracker.py", line 92, in add
      raise LookupError(message)
  LookupError: https://files.pythonhosted.org/packages/aa/5b/62165da80cbc6e1779f342234c7ddc6c6bc9e64cef149046a9c0456f912b/tomli-1.2.2.tar.gz#sha256=c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee (from https://pypi.org/simple/tomli/) (requires-python:>=3.6) is already being built: tomli>=1.2.1 from https://files.pythonhosted.org/packages/aa/5b/62165da80cbc6e1779f342234c7ddc6c6bc9e64cef149046a9c0456f912b/tomli-1.2.2.tar.gz#sha256=c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee (from setuptools-rust>=0.11.4)
  ----------------------------------------
WARNING: Discarding https://files.pythonhosted.org/packages/75/50/973397c5ba854445bcc396b593b5db1958da6ab8d665b27397daa1497018/tomli-1.2.1.tar.gz#sha256=a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442 (from https://pypi.org/simple/tomli/) (requires-python:>=3.6). Command errored out with exit status 2: /home/pi/.platformio/penv/bin/python /tmp/pip-standalone-pip-sgkbdzl6/__env_pip__.zip/pip install --ignore-installed --no-user --prefix /tmp/pip-build-env-zwmgu3x5/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple --extra-index-url https://www.piwheels.org/simple --extra-index-url https://www.piwheels.org/simple -- 'flit_core>=3.2.0,<4' Check the logs for full command output.
Collecting setuptools-rust>=0.11.4
  Using cached setuptools-rust-0.12.1.tar.gz (282 kB)
  Installing build dependencies: started
  Installing build dependencies: still running...
  Installing build dependencies: finished with status 'done'
  Getting requirements to build wheel: started
  Getting requirements to build wheel: finished with status 'done'
  Installing backend dependencies: started
  Installing backend dependencies: finished with status 'done'
  Preparing metadata (pyproject.toml): started
  Preparing metadata (pyproject.toml): finished with status 'done'
Collecting semantic-version>=2.6.0
  Using cached semantic_version-2.8.5.tar.gz (50 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Collecting toml>=0.9.0
  Using cached toml-0.10.2.tar.gz (22 kB)
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Skipping wheel build for wheel, due to binaries being disabled for it.
Skipping wheel build for cffi, due to binaries being disabled for it.
Skipping wheel build for semantic-version, due to binaries being disabled for it.
Skipping wheel build for toml, due to binaries being disabled for it.
Skipping wheel build for pycparser, due to binaries being disabled for it.
Building wheels for collected packages: setuptools-rust, setuptools
  Building wheel for setuptools-rust (pyproject.toml): started
  Building wheel for setuptools-rust (pyproject.toml): finished with status 'done'
  Created wheel for setuptools-rust: filename=setuptools_rust-0.12.1-py3-none-any.whl size=22068 sha256=592ee8d73230f07f4d3a4dcdcac471d9774d5fdf6cb510dfd4e1c5c85defe013
  Stored in directory: /home/pi/.cache/pip/wheels/0d/74/4c/815dea1b32e070a03f3bdebc2ac66dec872e2f4f98873de7f1
  Building wheel for setuptools (pyproject.toml): started
  Building wheel for setuptools (pyproject.toml): finished with status 'done'
  Created wheel for setuptools: filename=setuptools-59.3.0-py3-none-any.whl size=952222 sha256=71c50c4701d693604255b3207d628d6be5b2a1c11735779cc532b8b4fad526b0
  Stored in directory: /home/pi/.cache/pip/wheels/b3/8b/0d/a37778f8f97ff4a4f7d1464a2f71fe824647a93b6407036e4f
Successfully built setuptools-rust setuptools
Installing collected packages: toml, setuptools, semantic-version, pycparser, wheel, setuptools-rust, cffi
    Running setup.py install for toml: started
    Running setup.py install for toml: finished with status 'done'
    Running setup.py install for semantic-version: started
    Running setup.py install for semantic-version: finished with status 'done'
    Running setup.py install for pycparser: started
    Running setup.py install for pycparser: finished with status 'done'
    Running setup.py install for wheel: started
    Running setup.py install for wheel: finished with status 'done'
    Running setup.py install for cffi: started
    Running setup.py install for cffi: finished with status 'error'
    ERROR: Command errored out with exit status 1:
     command: /home/pi/.platformio/penv/bin/python -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-d0sgr43l/cffi_1f03051e252344d59bd5ebdf4f5e0f48/setup.py'"'"'; __file__='"'"'/tmp/pip-install-d0sgr43l/cffi_1f03051e252344d59bd5ebdf4f5e0f48/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-hy0iyr4f/install-record.txt --single-version-externally-managed --prefix /tmp/pip-build-env-z_7hwbt9/overlay --compile --install-headers /tmp/pip-build-env-z_7hwbt9/overlay/include/site/python3.9/cffi
         cwd: /tmp/pip-install-d0sgr43l/cffi_1f03051e252344d59bd5ebdf4f5e0f48/
    Complete output (58 lines):
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    Package libffi was not found in the pkg-config search path.
    Perhaps you should add the directory containing `libffi.pc'
    to the PKG_CONFIG_PATH environment variable
    No package 'libffi' found
    running install
    /home/pi/.platformio/penv/lib/python3.9/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
      warnings.warn(
    running build
    running build_py
    creating build
    creating build/lib.linux-armv7l-3.9
    creating build/lib.linux-armv7l-3.9/cffi
    copying cffi/commontypes.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/cparser.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/setuptools_ext.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/pkgconfig.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/__init__.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/model.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/verifier.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/recompiler.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/ffiplatform.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/error.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/vengine_cpy.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/backend_ctypes.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/vengine_gen.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/lock.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/cffi_opcode.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/api.py -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/_cffi_include.h -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/parse_c_type.h -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/_embedding.h -> build/lib.linux-armv7l-3.9/cffi
    copying cffi/_cffi_errors.h -> build/lib.linux-armv7l-3.9/cffi
    running build_ext
    building '_cffi_backend' extension
    creating build/temp.linux-armv7l-3.9
    creating build/temp.linux-armv7l-3.9/c
    arm-linux-gnueabihf-gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O2 -Wall -g -ffile-prefix-map=/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -g -fwrapv -O2 -g -ffile-prefix-map=/python3.9-3.9.2=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -DUSE__THREAD -DHAVE_SYNC_SYNCHRONIZE -I/usr/include/ffi -I/usr/include/libffi -I/home/pi/.platformio/penv/include -I/usr/include/python3.9 -c c/_cffi_backend.c -o build/temp.linux-armv7l-3.9/c/_cffi_backend.o
    c/_cffi_backend.c:15:10: fatal error: ffi.h: No such file or directory
       15 | #include <ffi.h>
          |          ^~~~~~~
    compilation terminated.
    error: command '/usr/bin/arm-linux-gnueabihf-gcc' failed with exit code 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /home/pi/.platformio/penv/bin/python -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-d0sgr43l/cffi_1f03051e252344d59bd5ebdf4f5e0f48/setup.py'"'"'; __file__='"'"'/tmp/pip-install-d0sgr43l/cffi_1f03051e252344d59bd5ebdf4f5e0f48/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-hy0iyr4f/install-record.txt --single-version-externally-managed --prefix /tmp/pip-build-env-z_7hwbt9/overlay --compile --install-headers /tmp/pip-build-env-z_7hwbt9/overlay/include/site/python3.9/cffi Check the logs for full command output.
----------------------------------------

Solution:

Install libffi-dev in order for the dependencies to install properly:

sudo apt -y install libffi-dev

 

Posted by Uli Köhler in Allgemein

How to compute SHA hash of local file in Javascript using SubtleCrypto API

The following example uses the SubtleCrypto API to compute the SHA-256 hash of a file that is selected in a file input. The checksum is computed entirely on the client side, the file does not need to be uploaded to a server at all.

This code has been verified to generate the same checksum as if running sha256sum on the command line.

Full example

You can download this file, save it as index.html and open it in the browser. Then select a file and check the develper

<html>
<body>
    <input type="file" id="myfile" onchange="onMyfileChange(this)" />

    <script src="https://unpkg.com/[email protected]/dist/jszip.js" type="text/javascript"></script>
    <script type="text/javascript">
        function onMyfileChange(fileInput) {
            if(fileInput.files[0] == undefined) {
                return ;
            }

            var filename = fileInput.files[0].name;
            // var filesize = fileInput.files[0].size;
            var reader = new FileReader();
            reader.onload = function(ev) {
                console.log("File", filename, ":");
                // 
                crypto.subtle.digest('SHA-256', ev.target.result).then(hashBuffer => {
                    // Convert hex to hash, see https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#converting_a_digest_to_a_hex_string
                    const hashArray = Array.from(new Uint8Array(hashBuffer));
                    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string
                    console.log(hashHex);
                }).catch(ex => console.error(ex));
            };
            reader.onerror = function(err) {
                console.error("Failed to read file", err);
            }
            reader.readAsArrayBuffer(fileInput.files[0]);
        }
    </script>
</body>
</html>
Posted by Uli Köhler in Javascript

How I fixed Tasmota 9.2.0 Nous A1 not auto-discovering in Home-Assistant

My Nous A1 flashed to Tasmota using tuya-convert worked fine using the webinterface and logged in successfully to the mosquitto MQTT server. However, Home-Assistant did not automatically discover it.

First, I logged into the Tasmota device console using the webinterface, enabled autodiscovery using

SetOption19 1

This alone did not help.

Then I upgraded Tasmota to 10.0.0 using the web update method via the webinterface. This took about 45 seconds and after that, the Nous A1 was automatically discovered by Home-Assistant. Hence, I recommend upgrading Tasmota to the most recent version before checking for any other issue. Note that checking the mosquitto logfile and the Tasmota console was also helpful because it showed that the device was successfully logging into MQTT and sending messages.

Posted by Uli Köhler in Allgemein

How to fix Caddy container generating docker volume with autosave.json

My docker-compose-based Caddy setup re-created the container and hence created a new docker volume with only the autosave.json whenever it was restarted. Since it was auto-restarted once a minute, this led do over 70000 volumes piling up in /var/lib/docker/volumes.

The Caddy log shows that Caddy is creating /config/caddy/autosave.json:

mycaddy_1 | {"level":"info","ts":1637877640.7375677,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}

I fixed this by mapping /config/caddy to a local directory:

- ./caddy_data:/config/caddy/

Complete docker-compose.yml example:

version: '3.5'
services:
  mycaddy:
    image: 'caddy:2.4.6-alpine'
    volumes:
      - ./caddy_data:/config/caddy/
      - ./static:/usr/share/caddy
      - ./Caddyfile:/etc/caddy/Caddyfile
    ports:
      - 19815:80

 

Posted by Uli Köhler in Docker, Networking

How to fix mosquitto local-only mode despite ‘listener 1883’

If mosquitto is printing the local only message even though you have listener 1883 in your config file, check if mosquitto is using the correct config file. In my case, I mis-spelled the config file path (conf instead of config), hence mosquitto used the default config file, not my config file and therefore ignored all statements I put in my config file.

Posted by Uli Köhler in MQTT, Networking

How to fix Mosquitto ‘exited with code 13’

When mosquitto exits with code 13 such as a in a docker based setup, you will often see not error messsage:

Attaching to mosquitto_mosquitto_1
mosquitto_mosquitto_1 exited with code 13

However, there will be an error message in mosquitto.logSo, ensure that you have configured a log_dest file in your mosquitto.conf such as:

log_dest file /mosquitto/log/mosquitto.log

and check that file. In my case it showed these error messages:

1637860284: mosquitto version 2.0.14 starting
1637860284: Config loaded from /mosquitto/config/mosquitto.conf.
1637860284: Error: Unable to open pwfile "/mosquitto/conf/mosquitto.passwd".
1637860284: Error opening password file "/mosquitto/conf/mosquitto.passwd".

In my case, the path of the password file was mis-spelled (conf instead of config)

Note that you need to create the password file in order for mosquitto to start up!

See How to setup standalone mosquitto MQTT broker using docker-compose for example commands on how to create the user and the password file

 

Posted by Uli Köhler in Docker, MQTT

How to disable mosquitto MQTT local-only mode and listen on all IP addresses

When starting Mosquitto using a default configuration file, you will see log message like

mosquitto_1  | 1637858580: Starting in local only mode. Connections will only be possible from clients running on this machine.

indicating that the mosquitto MQTT broker is only listening on 127.0.0.1 and is not reachable over the network.

In order to fix this, you can simply bind to all IP addresses using

bind_address 0.0.0.0
listener 1883

in mosquitto.conf

Full mosquitto.conf example

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log

listener 1883
## Authentication ##
allow_anonymous false
password_file /mosquitto/conf/mosquitto.conf

See our previous post on How to setup standalone mosquitto MQTT broker using docker-compose for further details on how to setup a mosquitto MQTT broker using this config.

If mosquitto is still printing the local only message even though you have listener 1883 in your config file, check if mosquitto is using the correct config file. In my case, I mis-spelled the config file path (conf instead of config), hence mosquitto used the default config file, not my config file and therefore ignored all statements I put in my config file.

Posted by Uli Köhler in MQTT, Networking

How to setup standalone mosquitto MQTT broker using docker-compose

docker-compose.yml

version: "3"

services:
  mosquitto:
    image: eclipse-mosquitto
    network_mode: host
    volumes:
      - ./conf:/mosquitto/conf
      - ./data:/mosquitto/data
      - ./log:/mosquitto/log

Now create conf/mosquitto.conf

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log

listener 1883
## Authentication ##
# allow_anonymous false
password_file /mosquitto/conf/mosquitto.conf

Now create the first user using

docker-compose exec mosquitto mosquitto_passwd -c /mosquitto/conf/mosquitto.passwd mosquitto

You can optionally create more users using the -b (batch) flag instead of -c , supplying the password on the command line:

docker-compose exec mosquitto mosquitto_passwd -b /mosquitto/conf/mosquitto.passwd seconduser shoaCh3ohnokeathal6eeH2marei2o

Now start mosquitto using

docker-compose up

or create a systemd service to autostart it.

We are running mosquitto using network_mode: host. Mosquitto will, by default, listen on port 1883 (MQTT). You can configure more services using conf/mosquitto.conf, see this StackOverflow post for more info.

Posted by Uli Köhler in MQTT

How to setup Home-Assistant MQTT with username & password

The following setting in configuration.yml connects to a local mosquitto MQTT broker using username and password:

mqtt:
  broker: "127.0.0.1"
  username: "homeassistant"
  password: "iraughij3Phoh7ne9Aoxingi2eimoo"

Complete configuration.yml:

default_config:

http:
  use_x_forwarded_for: true
  trusted_proxies:
  - 127.0.0.1
  ip_ban_enabled: true
  login_attempts_threshold: 5

mqtt:
  broker: "127.0.0.1"
  username: "homeassistant"
  password: "iraughij3Phoh7ne9Aoxingi2eimoo"

# Text to speech
tts:
  - platform: google_translate

group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml

 

Posted by Uli Köhler in Home-Assistant, MQTT

How to fix mosquitto_passwd overwriting all other users in the password file

Problem:

When running mosquitto_passwd like this:

docker-compose exec mosquitto mosquitto_passwd /mosquitto/conf/mosquitto.passwd myuser

or with the -c parameter:

docker-compose exec mosquitto mosquitto_passwd -c /mosquitto/conf/mosquitto.passwd myuser

the user is created but all other users who where previously listed in the file are deleted.

Solution:

Create the first user using the -c flag in order to create the file if it does not exist

docker-compose exec mosquitto mosquitto_passwd -c /mosquitto/conf/mosquitto.passwd firstuser

Then create additional users using -b (batch mode),which allows you to specify the password on the command line:

docker-compose exec mosquitto mosquitto_passwd -b /mosquitto/conf/mosquitto.passwd seconduser shoaCh3ohnokeathal6eeH2marei2o

When using -b, old users will not be deleted.

Posted by Uli Köhler in MQTT

How to fix Home-Assistant A request from a reverse proxy was received from 127.0.0.1, but your HTTP integration is not set-up for reverse proxies

Problem:

When running home-assistant (using docker or other methods) behind a reverse proxy such as nginx, you see 400: Bad request response codes and the following error message appears in the HomeAssistant logs:

homeassistant    | 2021-11-25 03:03:59 ERROR (MainThread) [homeassistant.components.http.forwarded] A request from a reverse proxy was received from 127.0.0.1, but your HTTP integration is not set-up for reverse proxies

Solution:

Edit config/configuration.yaml and add:

http:
  use_x_forwarded_for: true
  trusted_proxies:
  - 127.0.0.1
  ip_ban_enabled: true
  login_attempts_threshold: 5

just below the default_config: line, adding a newline in between.   If your reverse proxy is running on another host, replace 127.0.0.1 by the IP address of that host.

Complete configuration.yml example:

# Configure a default setup of Home Assistant (frontend, api, etc)
default_config:

http:
  use_x_forwarded_for: true
  trusted_proxies:
  - 127.0.0.1
  ip_ban_enabled: true
  login_attempts_threshold: 5

# Text to speech
tts:
  - platform: google_translate

group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml

Now restart home-assistant and your reverse proxy should work fine.

Posted by Uli Köhler in Home-Assistant

How to fix Docker Home-Assistant [finish] process exit code 256

Problem:

Your Docker container running home-assistant always exits immediately after starting up, with the log being similar to this:

$ docker-compose up
Recreating homeassistant ... done
Attaching to homeassistant
homeassistant    | [s6-init] making user provided files available at /var/run/s6/etc...exited 0.
homeassistant    | [s6-init] ensuring user provided files have correct perms...exited 0.
homeassistant    | [fix-attrs.d] applying ownership & permissions fixes...
homeassistant    | [fix-attrs.d] done.
homeassistant    | [cont-init.d] executing container initialization scripts...
homeassistant    | [cont-init.d] done.
homeassistant    | [services.d] starting services
homeassistant    | [services.d] done.
homeassistant    | [finish] process exit code 256
homeassistant    | [finish] process received signal 15
homeassistant    | [cont-finish.d] executing container finish scripts...
homeassistant    | [cont-finish.d] done.
homeassistant    | [s6-finish] waiting for services.
homeassistant    | [s6-finish] sending all processes the TERM signal.
homeassistant    | [s6-finish] sending all processes the KILL signal and exiting.
homeassistant exited with code 0

Solution:

You need to start the container with --privileged=true if using docker directly to start up the service, or use privileged: true if using docker-compose.

Here’s an example of a working docker-compose.yml file:

version: '3.5'
services:
  homeassistant:
    container_name: homeassistant
    restart: unless-stopped
    image: ghcr.io/home-assistant/home-assistant:stable
    network_mode: host
    privileged: true
    environment:
      - TZ=Europe/Berlin
    volumes:
      - ./config:/config

https://techoverflow.net/wp-admin/post-new.php#category-all

Posted by Uli Köhler in Container, Docker, Home-Assistant

How I fixed tuya-convert Nous A1 SmartConfig complete. Resending SmartConfig Packets loop

Problem:

While trying to flash a device using tuya-convert, you see an error message like

======================================================
Starting smart config pairing procedure
Waiting for the device to install the intermediate firmware
Put device in EZ config mode (blinking fast)
Sending SSID                  vtrust-flash
Sending wifiPassword          
Sending token                 00000000
Sending secret                0101
................
SmartConfig complete.
Resending SmartConfig Packets
.................
SmartConfig complete.
Resending SmartConfig Packets
.................
SmartConfig complete.
Resending SmartConfig Packets
................
SmartConfig complete.
Resending SmartConfig Packets
.................
SmartConfig complete.
Resending SmartConfig Packets
.................
SmartConfig complete.
Resending SmartConfig Packets
................
SmartConfig complete.
Resending SmartConfig Packets
.................
SmartConfig complete.
Resending SmartConfig Packets
.................
SmartConfig complete.
Resending SmartConfig Packets
................
SmartConfig complete.
Resending SmartConfig Packets
..............
Timed out while waiting for the device to (re)connect

and the flash procedure fails.

Solution:

You can see the actual error log in scripts/smarthack-psk.log. In my case the error was the one described in our previous post How I fixed tuya-convert Nous A1 could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher

The current version of ./install_reqs.sh does not install the sslpsk module correctly (the error message is somewhat hidden at the top of the log). Install it manually using

sudo -H python3 -m pip install --upgrade sslpsk

 

Posted by Uli Köhler in Electronics, Embedded

How I fixed tuya-convert Nous A1 could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher

Problem:

While trying to flash a device using tuya-convert, you see an error message like

Traceback (most recent call last):
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 6, in <module>
    import sslpsk
ModuleNotFoundError: No module named 'sslpsk'
Traceback (most recent call last):
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 6, in <module>
    import sslpsk
ModuleNotFoundError: No module named 'sslpsk'
new client on port 443 from 10.42.42.10:49144
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49150
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49154
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49156
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49160
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49162
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49164
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49172
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49174
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49176
could not establish sslpsk socket: [SSL: NO_SHARED_CIPHER] no shared cipher (_ssl.c:1123)
don't panic this is probably just your phone!
new client on port 443 from 10.42.42.10:49178
could not establish sslpsk socket: EOF occurred in violation of protocol (_ssl.c:1123)
Traceback (most recent call last):
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 61, in new_client
    ssl_sock = sslpsk.wrap_socket(s1,
  File "/usr/local/lib/python3.9/dist-packages/sslpsk/sslpsk.py", line 110, in wrap_socket
    sock.do_handshake()
  File "/usr/lib/python3.9/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1123)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 113, in <module>
    main()
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 109, in main
    p.data_ready_cb(s)
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 80, in data_ready_cb
    self.new_client(_s)
  File "/home/pi/tuya-convert/scripts/./psk-frontend.py", line 72, in new_client
    if "NO_SHARED_CIPHER" in e.reason or "WRONG_VERSION_NUMBER" in e.reason or "WRONG_SSL_VERSION" in e.reason:
TypeError: argument of type 'NoneType' is not iterable

and the flash procedure fails.

Solution:

The current version of ./install_reqs.sh does not install the sslpsk module correctly (the error message is somewhat hidden at the top of the log). Install it manually using

sudo -H python3 -m pip install --upgrade sslpsk

 

Posted by Uli Köhler in Electronics, Embedded

How to fix tuya-convert ModuleNotFoundError: No module named ‘Cryptodome’

Problem:

While trying to flash a device using tuya-convert, you see an error message like

======================================================
Starting smart config pairing procedure
Waiting for the device to install the intermediate firmware
Traceback (most recent call last):
  File "/home/pi/tuya-convert/scripts/./smartconfig/main.py", line 15, in <module>
    from smartconfig import smartconfig
  File "/home/pi/tuya-convert/scripts/smartconfig/smartconfig.py", line 43, in <module>
    from multicast import multicast_head, encode_multicast_body
  File "/home/pi/tuya-convert/scripts/smartconfig/multicast.py", line 12, in <module>
    from Cryptodome.Cipher import AES
ModuleNotFoundError: No module named 'Cryptodome'
.........................................

and the flash procedure fails.

Solution:

The current version of ./install_reqs.sh does not install the pycryptodome module. Install it manually using

sudo -H python3 -m pip install --upgrade pycryptodome

 

Posted by Uli Köhler in Electronics, Embedded

How to pass firewall using PlatformIO espota ArduinOTA upload

ArduinoOTA’s protocol tries to connect to the host which is trying to program the device on a randomly chosen port. This often leads to the packets being filtered in a firewall since no rule exists to pass the packet and they are not related to an existing connection.

You could create a firewall rule to pass all traffic from the ESP8266/ESP32 to the programming host, but that is extremely insecure since it allows a hacked IoT device to hack your devices.

In order to fix it, add a fixed host port in platformio.ini using

upload_flags = --host_port=55910

and add these firewall rules:

allow from <programming host> to <IoT device> port 55910 TCP
allow from <IoT device> to <programming host> port 55190 TCP

Complete platformio.ini example:

[env:d1_mini_ota]
extends = env:d1_mini
upload_protocol = espota
upload_port = 192.168.178.25
upload_flags = --host_port=55910

 

Posted by Uli Köhler in Embedded, ESP8266/ESP32, PlatformIO

How to cool down Extruder using G-Code (Marlin)

Use M104 to cool down the extruder:

M104S0 ; Cooldown hotend

 

 

Posted by Uli Köhler in 3D printing
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Cookie settingsACCEPTPrivacy &amp; Cookies Policy