[RPI] WTW aansturing: GPIO events blijven continu triggeren

Pagina: 1
Acties:

Vraag


  • MaNdM
  • Registratie: April 2001
  • Laatst online: 26-09 21:03

MaNdM

1000-dingen-doekje

Topicstarter
Laat ik even vooraf erbij vermelden dat dit mijn allereerste RPI project is waar ik de GPIO gebruik in combinatie met python. Zowel de taal als GPIO zijn voor mij nieuw.

Mijn projectje
Ik wil onze WTW die je aanstuurt met een drie-standen-schakelaar gaan aansturen via domotica in combinatie met de fysieke schakelaar. De regels zijn relatief simpel: als de fysieke schakelaar gebruikt wordt dient die instelling altijd de huidige stand te vervangen. Als via een web-request een stand wordt ingesteld dan wordt dat de stand totdat ofwel de fysieke knop gebruikt wordt of er een nieuwe web-request wordt gedaan.

De reden voor het gebruiken van een webrequest is simpel: ik heb alles via Homey draaien en een GET request is de makkelijkste route in dit geval.

Theorie aanpak
Mij leek het gebruik van een raspberry pi in combinatie met een relais bordje de beste route. Het relais bordje gebruik ik om de 12V signalen van de WTW te schakelen. De fysieke standen schakelaar koppel ik aan GPIO pinnen. Met python en Flask maak ik een app waar ik de events afvang van de GPIO input pins en de GET requests en bob is je oom.

De werkelijkheid
In mijn tests werkte het geheel perfect, tot ik de standen schakelaar in gebruik nam. Want wat ik nu zie gebeuren is dat ongeacht de stand het bijbehorende event de hele tijd opnieuw blijft triggeren.
Afbeeldingslocatie: https://tweakers.net/i/p1R6F-2xaox-3kH3B324WGinjts=/800x/filters:strip_exif()/f/image/MdCUXLYM1pirbX0eTE4XluXC.png?f=fotoalbum_large

De knop staat toch echt stil, dus waarom blijft dat event de hele tijd opnieuw komen? Ik heb al geprobeerd om de aansturing te doen op basis van pull-down en ook pull-up. Uiteindelijk maakt het geen verschil.

Natuurlijk heb ik ook gemeten hoeveel volt er op de pin staat bij een actieve stand (0,1V bij pull-down situatie) en volgens mij zit het altijd ver genoeg af van de grenzen voor de rizing danwel falling edge.

Wat natuurlijk ook anders is ten opzichte van mijn testopstelling is dat er natuurlijk langere draden in gebruik zijn. Tussen de rpi en de standenschakelaar zit een CAT5 netwerk kabel waar vier paren zijn gemaakt voor de vier mogelijke signalen. Drie paren voor de standen en een extra paar voor de filter LED, deze is nu niet in gebruik.

Ik doe vast vanalles fout. Aangezien het geheel keurig werkt zodra ik de schakelaar er tussenuit laat en met kabeltjes direct op de GPIO header werk lijkt het me duidelijk dat het te maken heeft met de schakelaar en/of de draadlengte. De schakelaar en de draad ga ik niet zomaar even vervangen dus ik hoop dat er een oplossing mogelijk is in de code of door een schakeling tussen te voegen.

De laatste versie van mijn code:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import RPi.GPIO as GPIO
from flask import Flask, render_template, request
import logging
from time import sleep

app = Flask(__name__)

logging.basicConfig(filename='record.log', level=logging.DEBUG, format=f'%(asctime)s %(levelname)s %(name)s %(threadName)s : %(message)s')

app.logger.info('App started')

GPIO.setmode(GPIO.BCM)

# Create a dictionary called pins to store the pin number, name, and pin state:
inputpins = {
   19 : {'name' : 'GPIO 19'},
   16 : {'name' : 'GPIO 16'}
   }

# Set each pin as an output and make it low:
for pin in inputpins:
   GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
   GPIO.input(pin)

pins = {
   20 : {'name' : 'GPIO 20', 'state' : GPIO.LOW},
   21 : {'name' : 'GPIO 21', 'state' : GPIO.LOW},
   26 : {'name' : 'GPIO 26', 'state' : GPIO.LOW}
   }

# Set each pin as an output and make it low:
for pin in pins:
   GPIO.setup(pin, GPIO.OUT)
   GPIO.output(pin, GPIO.LOW)

# WTW standen
#    L   L   G
#    |   |   |
# 1  0   0
# 2  1   0
# 3  0   1

def set_level():
   if GPIO.input(19) == 0:
      print('Input 19 is low')
      app.logger.info('Input 19 is low')
      GPIO.output(20, GPIO.LOW)
      GPIO.output(21, GPIO.HIGH)
      GPIO.output(26, GPIO.LOW)
   if GPIO.input(16) == 0:
      print('Input 16 is low')
      app.logger.info('Input 16 is low')
      GPIO.output(20, GPIO.HIGH)
      GPIO.output(21, GPIO.LOW)
      GPIO.output(26, GPIO.LOW)
   if GPIO.input(16) == 1 and GPIO.input(19) == 1:
      print('Input 16 and 19 are high')
      app.logger.info('Input 16 and 19 are high')
      GPIO.output(20, GPIO.LOW)
      GPIO.output(21, GPIO.LOW)
      GPIO.output(26, GPIO.HIGH)

def my_callback(channel):
    sleep(0.2)
    print('Callback function triggered by pin ' + str(channel) + ', setting level')
    app.logger.info('Callback function triggered, setting level')
    set_level()

GPIO.add_event_detect(19, GPIO.BOTH, callback=my_callback, bouncetime=100)
GPIO.add_event_detect(16, GPIO.BOTH, callback=my_callback, bouncetime=100)
set_level()

@app.route("/")
def main():
   # For each pin, read the pin state and store it in the pins dictionary:
   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin)
   # Put the pin dictionary into the template data dictionary:
   templateData = {
      'pins' : pins
      }
   # Pass the template data into the template main.html and return it to the user
   return render_template('main.html', **templateData)

@app.route("/release")
def release():
   print('Release triggered')
   app.logger.info('Release triggered')
   set_level()

   # For each pin, read the pin state and store it in the pins dictionary:
   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin)
   # Put the pin dictionary into the template data dictionary:
   templateData = {
      'pins' : pins
      }
   # Pass the template data into the template main.html and return it to the user
   return render_template('main.html', **templateData)

# The function below is executed when someone requests a URL with the pin number and action in it:
@app.route("/<changePin>/<action>")
def action(changePin, action):
   print('Pin change requested')
   app.logger.info('Pin change requested')
   # Convert the pin from the URL into an integer:
   changePin = int(changePin)
   # Get the device name for the pin being changed:
   deviceName = pins[changePin]['name']
   # If the action part of the URL is "on," execute the code indented below:
   if action == "on":
      # Set the pin high:
      for pin in pins:
         if pin == changePin:
            GPIO.output(pin, GPIO.HIGH)
         else:
            GPIO.output(pin, GPIO.LOW)
      # Save the status message to be passed into the template:
      message = "Turned " + deviceName + " on."
   if action == "off":
      GPIO.output(changePin, GPIO.LOW)
      message = "Turned " + deviceName + " off."

   # For each pin, read the pin state and store it in the pins dictionary:
   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin)

   # Along with the pin dictionary, put the message into the template data dictionary:
   templateData = {
      'pins' : pins
   }

   return render_template('main.html', **templateData)

if __name__ == "__main__":
   app.run(host='0.0.0.0', port=80, debug=True)

To be determined...

Alle reacties


  • Bloodhoundje
  • Registratie: September 2003
  • Laatst online: 26-09 13:26
Zou je naast de code ook een tekening kunnen maken van het bedradingsschema, mogelijk zit er een fout in je bedrading. potentiaalverschil etc waardoor dit ook kan gebeuren. Met dit erbij kunnen wij code/hardware vergelijken en mogelijk sneller een oorzaak voor je achterhalen :)

  • memphis
  • Registratie: Oktober 2000
  • Laatst online: 14:53

memphis

48k was toen meer dan genoeg.

Op inputs is het handig om pull up of pull down weerstanden te gebruiken. Vaak kan je die ook op een GPIO activeren.

Er zijn mensen die mij een GOD vinden


  • MaNdM
  • Registratie: April 2001
  • Laatst online: 26-09 21:03

MaNdM

1000-dingen-doekje

Topicstarter
Bloodhoundje schreef op donderdag 11 augustus 2022 @ 19:48:
Zou je naast de code ook een tekening kunnen maken van het bedradingsschema, mogelijk zit er een fout in je bedrading. potentiaalverschil etc waardoor dit ook kan gebeuren. Met dit erbij kunnen wij code/hardware vergelijken en mogelijk sneller een oorzaak voor je achterhalen :)
Goed punt. Ik zal even moeten kijken hoe ik dat het makkelijkste kan maken.

Ik heb natuurlijk niet stilgezeten en ik denk dat ik een oplossing heb gevonden. In mijn zoektocht naar mogelijke oorzaken kwam ik natuurlijk op het "debouncen" van de switch uit. Hier vond ik onderstaand schema en deze heb ik toegepast. Ik heb een andere waarde condensator (4.7uF) gebruikt en de weerstand (1kOhm) daarop aangepast.
Afbeeldingslocatie: https://tweakers.net/i/v5luG26HW7-vPF09iAuzGBw_pzg=/800x/filters:strip_exif()/f/image/TGIPRkOQeQZYEov0nqZoW3A8.png?f=fotoalbum_large

Deze aanpassing heeft het probleem opgelost. Ik denk dat er ruis in het signaal zat en dat heb ik er nu uit kunnen halen. Tot dusver lijkt het nu stabiel en zie ik geen valse triggers meer voorbij komen.
memphis schreef op donderdag 11 augustus 2022 @ 20:13:
Op inputs is het handig om pull up of pull down weerstanden te gebruiken. Vaak kan je die ook op een GPIO activeren.
De optie om dit op de GPIO zelf te doen had ik al in gebruik. Het probleem zit denk ik in de ruis bij een van de contacten.

Edit:
Hoewel het al veel stabieler is gebeuren er toch nog gekke dingen. Toen ik gisteren op de zolder was en de lamp daar uit ging (gaat via bewegingsmelder) triggerde dit blijkbaar een event. Vanmorgen is er zonder reden drie keer binnen een seconde een event getriggerd.

Het is dus toch nog niet helemaal opgelost helaas. Moet ik condensators pakken met een hogere waarde? Zou dat helpen?

[ Voor 10% gewijzigd door MaNdM op 12-08-2022 09:08 ]

To be determined...


Acties:
  • 0 Henk 'm!

  • Slonzo
  • Registratie: Mei 2007
  • Niet online

Slonzo

Taarsidath-an Halsaam

Ik heb je script niet doorgenomen, maar je kan ook gewoon software debouncing toepassen ipv in hardware (duplicate events binnen de x milliseconden negeren).

Acties:
  • 0 Henk 'm!

  • MaNdM
  • Registratie: April 2001
  • Laatst online: 26-09 21:03

MaNdM

1000-dingen-doekje

Topicstarter
Slonzo schreef op zaterdag 13 augustus 2022 @ 13:41:
Ik heb je script niet doorgenomen, maar je kan ook gewoon software debouncing toepassen ipv in hardware (duplicate events binnen de x milliseconden negeren).
Klopt, dat heb ik geprobeerd en dat scheelde iets. De toevoeging van de condensators heeft nu eigenlijk het meeste effect. Wat opvalt is dat als er rond die stroom daar iets aan of uit gaat dit nu ook tot een event leidt. Voorbeelden hiervan zijn:
  • Lamp zolder gaat aan of uit
  • Screen wat aangesloten is bij het stopcontact van de WTW gaat op of neer
Om de een of andere reden zit er storing in het geheel. En dat is eigenlijk wel gek, want de GPIO krijgt toch echt 3.3V of 0V. Ik heb het nagemeten en het zit niet dicht op een edge.

To be determined...


Acties:
  • +1 Henk 'm!

  • MaNdM
  • Registratie: April 2001
  • Laatst online: 26-09 21:03

MaNdM

1000-dingen-doekje

Topicstarter
Ik heb net iets gelezen dat de GPIO erg gevoelig is voor EMI. Dat komt overeen met wat ik zie gebeuren. Zodra er op 230V net iets schakelt wat in de buurt zit van mijn opstelling zie ik events triggeren.

In mijn code heb ik nu de pin status als lijst opgenomen en ik vergelijk de status na een halve seconde voordat ik daadwerkelijk iets ga doen. Als deze gelijk is aan wat de status voorheen was dan doe ik niks want het was waarschijnlijk een EMI spike.

Ik zie nu via de logging de door EMI veroorzaakte events nog wel, maar de acties blijven keurig achterwege. Aansturing via fysieke knop en GET requests gaat nu ook prima. Moet alleen de dubbele requests van de knop nog fixen maar dat is een minor detail.

To be determined...


Acties:
  • 0 Henk 'm!

  • Septillion
  • Registratie: Januari 2009
  • Laatst online: 14:17

Septillion

Moderator Wonen & Mobiliteit
Ik lijk in de code te zien dat je de pull up aan zet (pull_up_down=GPIO.PUD_UP) maar je juist de switch ook active high aansluit. Je pull moet de andere kant op dan je active state. De pull is er voor bedoelt dat de pin state in rust dus het tegenovergestelde is.

Dus:
OF schakelaar naar Vcc = active high en dan een pull down.
OF schakelaar naar GND = active low en dan een pull up.

Acties:
  • 0 Henk 'm!

  • dragonhaertt
  • Registratie: Februari 2011
  • Laatst online: 11:24

dragonhaertt

@_'.'

Storing op GPIO kan ook komen door storing in de voedingslijn. De rpi ziet het verschil niet tussen een wijziging op GPIO of de voeding, aangezien die met elkaar vergeleken worden.

Een goedkope voeding of instabiel voedingscircuit kan dit gedrag ook veroorzaken.

Truth is like a language with no native speakers left.
Its poetry is speechless and it can’t be caught in human being’s breath.


Acties:
  • 0 Henk 'm!

  • MaNdM
  • Registratie: April 2001
  • Laatst online: 26-09 21:03

MaNdM

1000-dingen-doekje

Topicstarter
dragonhaertt schreef op zondag 14 augustus 2022 @ 11:45:
Storing op GPIO kan ook komen door storing in de voedingslijn. De rpi ziet het verschil niet tussen een wijziging op GPIO of de voeding, aangezien die met elkaar vergeleken worden.

Een goedkope voeding of instabiel voedingscircuit kan dit gedrag ook veroorzaken.
Ik gebruik nu een Anker voeding van 2,1A. Zou dat niet genoeg zijn?

To be determined...


Acties:
  • 0 Henk 'm!

  • dragonhaertt
  • Registratie: Februari 2011
  • Laatst online: 11:24

dragonhaertt

@_'.'

MaNdM schreef op zondag 14 augustus 2022 @ 14:43:
[...]

Ik gebruik nu een Anker voeding van 2,1A. Zou dat niet genoeg zijn?
Geen idee hoe stabiel die is, en hoe goed de voeding-filtering op een RPi is. Het was meer een algemene opmerking over microcontrollers en ADC systemen.

Truth is like a language with no native speakers left.
Its poetry is speechless and it can’t be caught in human being’s breath.

Pagina: 1