{"id":29,"date":"2013-02-11T13:22:53","date_gmt":"2013-02-11T13:22:53","guid":{"rendered":"http:\/\/www.nicassio.it\/daniele\/blog\/?p=29"},"modified":"2013-02-11T13:22:53","modified_gmt":"2013-02-11T13:22:53","slug":"raspberry-pi-controlled-light-clapper","status":"publish","type":"post","link":"https:\/\/www.nicassio.it\/daniele\/blog\/?p=29","title":{"rendered":"Raspberry PI controlled Light Clapper"},"content":{"rendered":"<p>This is one of my first Raspberry PI projects, and consists of a Raspberry connected to a microphone which detects an hand clap and then controls via GPIO a relay that powers the lamp.<\/p>\n<p><iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"http:\/\/www.youtube.com\/embed\/eJCmQfhnnLQ\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n<p>The code used for the detecting the clap (which is not perfect, because it analyzes only the volume of the microphone) is this:<br \/>\n[actually this is not the same code used in the video above, it has been improved, in fact the delay between the two claps is reduced in this script]<\/p>\n<div style=\"background-color: rgba(255,0,0,0.3); border: 2px solid red; padding: 5px; line-height: 130%;\"><b>ATTENTION: UGLY CODE FOLLOWS.<\/b><br \/>\nThe code has been written only to provide a proof-of-concept project, and it&#8217;s written joining various pieces of code found in the Internet, so\u00a0<strong>don&#8217;t expect this code to be bug free or well written. It is not.<\/strong><br \/>\nYou should use it to understand the way it works and to write something better or to adapt it to your own project.<\/div>\n<pre>#!\/usr\/bin\/python\n\nimport urllib\nimport urllib2\nimport os, sys\nimport ast\nimport json\nimport os\nimport getpass, poplib\nfrom email import parser\nimport RPi.GPIO as GPIO\n\nfile = 'test.flac'\n\nimport alsaaudio, time, audioop\n\nclass Queue: \n    \"\"\"A sample implementation of a First-In-First-Out\n       data structure.\"\"\"\n    def __init__(self):\n        self.size = 35\n        self.in_stack = []\n        self.out_stack = []\n        self.ordered = []\n        self.debug = False\n    def push(self, obj):\n        self.in_stack.append(obj)\n    def pop(self):\n        if not self.out_stack:\n            while self.in_stack:\n                self.out_stack.append(self.in_stack.pop())\n        return self.out_stack.pop()\n    def clear(self):\n        self.in_stack = []\n        self.out_stack = []\n    def makeOrdered(self):\n        self.ordered = []\n        for i in range(self.size):\n            #print i\n            item = self.pop()\n            self.ordered.append(item)\n            self.push(item)\n\n        if self.debug:\n            i = 0\n            for k in self.ordered:   \n                if i == 0: print \"-- v1 --\"\n                if i == 5: print \"-- v2 --\"\n                if i == 15: print \"-- v3 --\"\n                if i == 20: print \"-- v4 --\"\n                if i == 25: print \"-- v5 --\"\n\n                for h in range(int(k\/3)):\n                    sys.stdout.write('#')\n                print \"\"\n                i=i+1\n\n    def totalAvg(self):\n        tot = 0\n        for el in self.in_stack:\n            tot += el\n\n        for el in self.out_stack:\n            tot += el\n\n        return float(tot) \/ (len(self.in_stack) + len(self.out_stack))\n\n    def firstAvg(self):\n        tot = 0\n        for i in range(5):\n            tot += self.ordered[i]\n        return tot\/5.0\n\n    def secondAvg(self):\n        tot = 0\n        for i in range(5,15):\n            tot += self.ordered[i]\n        return tot\/10.0\n\n    def thirdAvg(self):\n        tot = 0\n        for i in range(15,20):\n            tot += self.ordered[i]\n        return tot\/5.0\n\n    def fourthAvg(self):\n        tot = 0\n        for i in range(20,30):\n            tot += self.ordered[i]\n        return tot\/10.0\n\n    def fifthAvg(self):\n        tot = 0\n        for i in range(30,35):\n            tot += self.ordered[i]\n        return tot\/5.0\n\ndef wait_for_sound():\n    GPIO.setmode(GPIO.BOARD)    \n    GPIO.setup(11, GPIO.OUT)\n\n    # Open the device in nonblocking capture mode. The last argument could\n    # just as well have been zero for blocking mode. Then we could have\n    # left out the sleep call in the bottom of the loop\n    card = 'sysdefault:CARD=Microphone'\n    inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK, card)\n\n    # Set attributes: Mono, 8000 Hz, 16 bit little endian samples\n    inp.setchannels(1)\n    inp.setrate(16000)\n    inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)\n\n    # The period size controls the internal number of frames per period.\n    # The significance of this parameter is documented in the ALSA api.\n    # For our purposes, it is suficcient to know that reads from the device\n    # will return this many frames. Each frame being 2 bytes long.\n    # This means that the reads below will return either 320 bytes of data\n    # or 0 bytes of data. The latter is possible because we are in nonblocking\n    # mode.\n    inp.setperiodsize(160)\n\n    last = 0\n    max = 0\n    clapped = False\n    out = False\n    fout = open(\"\/var\/www\/cgi-bin\/clapper\/killme\", \"w\")\n    fout.write('0n');\n    fout.close()\n\n    queue = Queue();\n    avgQueue = Queue();\n\n    n = 0; \n    n2=0;\n    while True:\n        fin = open(\"\/var\/www\/cgi-bin\/clapper\/killme\", \"r\")\n        if fin.readline() == \"1n\":\n            break;\n        fin.close()\n        # Read data from device\n        l,data = inp.read()\n        if l:\n            err = False\n            volume = -1\n            try:\n                volume = audioop.max(data, 2)\n            except: \n                print \"err\";\n                err = True\n            if err: continue\n\n            queue.push(volume)\n            avgQueue.push(volume)\n            n = n + 1\n            n2 = n2 + 1\n            if n2 &gt; 500:\n                avgQueue.pop()\n\n            if n &gt; queue.size:\n                avg = avgQueue.totalAvg()\n                print \"avg last fragments: \" + str(avg)\n\n                low_limit = avg + 10\n                high_limit = avg + 30\n\n                queue.pop();\n                queue.makeOrdered();\n                v1 = queue.firstAvg();\n                v2 = queue.secondAvg();\n                v3 = queue.thirdAvg();\n                v4 = queue.fourthAvg();\n                v5 = queue.fifthAvg();\n                if False:\n                    print \"v1: \"+str(v1)+\"n\"\n                    print \"v2: \"+str(v2)+\"n\"\n                    print \"v3: \"+str(v3)+\"n\"\n                    print \"v4: \"+str(v4)+\"n\"\n                    print \"v5: \"+str(v5)+\"n\"\n                #if v1 &lt; low_limit: print str(n)+\": v1 ok\"                 #if v2 &gt; high_limit: print str(n)+\": v2 ok\"\n                #if v3 &lt; low_limit: print str(n)+\": v3 ok\"                 #if v4 &gt; high_limit: print str(n)+\": v4 ok\"\n                #if v5 &lt; low_limit: print str(n)+\": v5 ok\"\n\n                if v1 &lt; low_limit and v2 &gt; high_limit and v3 &lt; low_limit and v4 &gt; high_limit and v5 &lt; low_limit:\n                    print str(time.time())+\": sgaMED\"\n                    out = not out\n                    GPIO.output(11, out)\n                    queue.clear()\n                    n = 0\n\n        time.sleep(.01)\n\nwait_for_sound()<\/pre>\n<p>&nbsp;<\/p>\n<p><code><\/code><br \/>\nThe code was found on the Internet and then adapted for my purposes. It uses a standard USB microphone, and should work with most of the linux-compatible USB mics (I think even webcam integrated mics).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is one of my first Raspberry PI projects, and consists of a Raspberry connected to a microphone which detects an hand clap and then controls via GPIO a relay that powers the lamp. The code used for the detecting the clap (which is not perfect, because it analyzes only the volume of the microphone) &hellip; <a href=\"https:\/\/www.nicassio.it\/daniele\/blog\/?p=29\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Raspberry PI controlled Light Clapper<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9,11],"tags":[],"_links":{"self":[{"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts\/29"}],"collection":[{"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=29"}],"version-history":[{"count":0,"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=\/wp\/v2\/posts\/29\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=29"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=29"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nicassio.it\/daniele\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=29"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}