Controlling GPIO from LXC container with python

Hi Guys,
My aim is to migrate my home automation system from the raspberry PI with home assistant to turris. The aim is to controll 433 MHz plug oultest like this project does: https://github.com/milaq/rpi-rf

My current problem is that under LXC I need to use the https://gitlab.labs.nic.cz/turris/python-turris-gpio python lib but this lib is compiled for the TurrisOS and doesn’t let to install it under the Debian LXC.
I can’t really use the RPi.GPIO lib as it is not compatible with the turris.

Do you guys have any idea how I should proceed?
Thank you

This might be little bit more challenging. I believe that you should be able to compile it but it won’t run in lxc unless you pass through some interfaces to lxc. I had it solved once so I might dig out some email where I described how to do it but it definitely wasn’t nice.

Digest from my emails:

… If so, it’s not supported. Although it can be done in default it won’t work. LXC
containers are separated from real hardware. Turris GPIO Python library support
two ways of access. First one is direct memory mapping. If that fails, it tries to
use /sys/class/gpio. I am not sure what happens if you try to do memory map on
absolute address in LXC, but I suspect it won’t work. So only other way is to use
it by rebind mounting /sys/class/gpio to container.

As first thing you have to allow access to /dev/mem from LXC container. In all of
these examples I am going to use lxc container names ubuntu, so replace it with
your name.
You have to add line “lxc.cgroup.devices.allow = c 1:1 rwm” to
/srv/lxc/ubuntu/config.
Next restart your lxc container.
Then to install gpio library, you have to clone repository (master branch) and run
command: python3 setup.py install --board=Omnia
You wrote that you already did this, so I won’t elaborate further. Just small
note, if you forgot to specify board, then you have to remove build directory
before running it again.
As next step you have to create /dev/mem inside container. So I would suggest
adding it somewhere to init. Command is "mknod -m 660 /dev/mem c 1 1"
And that should be all. I ran some small tests and it works. So I hope it helps
you.

Exposing /dev/mem to LXC is quite simple.
I had to add two extra lines to configuration:

lxc.cgroup.devices.allow = c 1:* rwm
lxc.mount.entry = /dev/mem dev/mem  none bind,optional,create=file 0 0

Then it shows in Debian without any additional steps.

Cool guys I will try it. In order to verify my setup at all I have ported the rpi-rf1 and tried it directly in the TurrisOS with python2. The receiver part worked, but the sender is not working. Signals are comming out but I guess there has to be a problem with the timing.

I will try the mapping prehaps it will work with Python3. Thank you

Super it worked!!! Thank you guys! The timing of the signal is not that good as with the PI though but I guess it is some other problem. Thank you for your support!!!

Fyi for those trying it I have pushed the manual and changes to the github… still WIP

LXC Running 433Mhz and a small manual

Native Turris Python2 433Mhz controll over python

still the timing for the GPIO is not very precise… I have to figure out why…

Bit banging protocol on non-realtime operating system is overall a bad idea. It somewhat works if system is not under load but it breaks if you try to use system to fullest. You would be more lucky if you would use uart or spi (depending on what those modules support, I don’t know them). Or use cheap microcontroller.

I had no luck in connecting my I2C sensor network directly to Omnia, so I did it in other way.
I have Arduino Pro Mini connected to UART1, and this drives entire network. I also hope that it will act as simple buffer - it will protect Omnia from any short circuits.

Good Feedback, guys I was somehow not aware I am doing Bit banging. I thought there is a kind of buffering, but yeah it’s just IO toggling. I have attached a logic analyzer and it can be nicly seen the gaps due to CPU busyness and interrupts…

It is a good idea using Ardunio…
Funny that with RaspPI it works so stable, should be the same issue there…

If that was all you were running on it then no it doesn’t have to have it. Because omnia is doing at least router stuff and that is definitely more that your raspi was doing (note 1G/100M network and also different connection so different handling, raspi just had less interrupts to handle).

Can you elaborate on that? (maybe in new topic)? I managed to run various hardware with i2c on omnia already (for example see: https://github.com/Cynerd/turris-ups-pfc8591). I might be able to help you.

My I2C network isn’t small: 11 devices on more than 40-50 meters of cat-5e cable. Part of it works with Omnia, all of them works only with AtMega as master.
I assume this may be current limitation on Omnia GPIO pins or something similar.

40-50 meters? I am not calculating it right now but my gut tells me that that is way over i2c impedance limits. Maybe if you use slowest speed and tweak pullup resistors but man I am not surprise that it doesn’t work with omnia. Omnia just doesn’t have powerful enough io to drive such impedance.

Wouldn’t be better to instead of all in i2c use just a localized i2c networks and connect those using some area network? Depending on what you want I would either use ethernet or can.

This is quite complicated network. I know that I2C specs says it should not work, but it works:)
Arduino drives this network using 100kHz - it is enough for me and it works with all devices.
Network includes:

  • 3 x DS2482 - I2C to one wire master - one near Omnia, two others on roof.
  • HDC 1080 + 3 x HDC1010 - humidity sensors spreaded over all flat, one is on roof
  • 2 x BH1750 - light intensity sensors on roof
  • 1 x AtMega as slave device - collects data from my weather station on roof
  • 1 I2C to GPIO - near Omnia, just in case of new ideas:)
  1. How did you access UART1 (which character device)?
  2. Which kernel-modules are necessary?
  3. Is it possible to access UART1 directly via registers?

UART1 (the one on GPIO header) is /dev/ttyS1
I have no special modules loaded to run it.
I’m accessing it via simple program written in C, but it should also work with “screen /dev/ttyS1”.