oldjake
Posts: 90
Joined: Fri Aug 03, 2018 12:39 pm

Struggling with structure of classes and functions

Sat Nov 24, 2018 5:58 pm

Hi all

I'm putting together some bits for occupancy detection. This is my first Python project and it's turning out a lot more involved than I'm probably capable of. This is the code I have:

This is my code:

Code: Select all

from bluepy.btle import Scanner, DefaultDelegate
import bluetooth
import MySQLdb
import mysql.connector
import sshtunnel
import time
import datetime

class ScanDelegate(DefaultDelegate):

	def __init__(self):
		DefaultDelegate.__init__(self)

	def handleDiscovery(self, dev, isNewDev, isNewData):
		ts = time.time()
		score = 0
		timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')

		if isNewDev:
			if "c1:ed:da:df:55:46" in dev.addr:
				sshtunnel.SSH_TIMEOUT = 30.0
				sshtunnel.TUNNEL_TIMEOUT = 30.0
				with sshtunnel.SSHTunnelForwarder(
					('ssh.pythonanywhere.com'),
					ssh_username='xxx', ssh_password='xxx',
					remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
				) as tunnel:
					connection = mysql.connector.connect(
						user='xxx', password='xxx',
						host='127.0.0.1', port=tunnel.local_bind_port,
						database='xxx$hivedashboard',
				)
					cursor = connection.cursor()
					status = "In"
					score = score + 5
					cursor.execute("UPDATE occupants SET status = %s, lastin = %s  WHERE occupants.id = '1'", (status, timestamp))
					connection.commit()
			else:
	 			sshtunnel.SSH_TIMEOUT = 30.0
				sshtunnel.TUNNEL_TIMEOUT = 30.0
				with sshtunnel.SSHTunnelForwarder(
					('ssh.pythonanywhere.com'),
					ssh_username='xxx', ssh_password='xxx',
					remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
				) as tunnel:
					connection = mysql.connector.connect(
						user='xxx', password='xxx',
						host='127.0.0.1', port=tunnel.local_bind_port,
						database='xxx$hivedashboard',
				)
					cursor = connection.cursor()
					status = "Out"
					cursor.execute("UPDATE occupants SET status = %s, lastout = %s  WHERE occupants.id = '1'", (status, timestamp))
					connection.commit()
		elif isNewData:
			print "Received new data from", dev.addr
scanner = Scanner().withDelegate(ScanDelegate())
devices = scanner.scan(10.0)

def others():
	sharonResult = bluetooth.lookup_name('8C:25:05:83:53:13', timeout=5)
	ts = time.time()
	timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
	if (sharonResult != None):
		sshtunnel.SSH_TIMEOUT = 30.0
		sshtunnel.TUNNEL_TIMEOUT = 30.0
		with sshtunnel.SSHTunnelForwarder(
			('ssh.pythonanywhere.com'),
			ssh_username='xxx', ssh_password='xxx',
			remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
		) as tunnel:
			connection = mysql.connector.connect(
				user='xxx', password='xxx',
				host='127.0.0.1', port=tunnel.local_bind_port,
				database='xxx$hivedashboard',
		)
			cursor = connection.cursor()
			status = "In"
			cursor.execute("UPDATE occupants SET status = %s, lastin = %s  WHERE occupants.id = '2'", (status, timestamp))
			connection.commit()
	    	score = score + 5
	else:
		sshtunnel.SSH_TIMEOUT = 30.0
		sshtunnel.TUNNEL_TIMEOUT = 30.0
		with sshtunnel.SSHTunnelForwarder(
			('ssh.pythonanywhere.com'),
			ssh_username='xxx', ssh_password='xxx',
			remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
		) as tunnel:
			connection = mysql.connector.connect(
				user='xxx', password='xxx',
				host='127.0.0.1', port=tunnel.local_bind_port,
				database='xxx$hivedashboard',
		)
			cursor = connection.cursor()
			status = "Out"
			cursor.execute("UPDATE occupants SET status = %s, lastout = %s  WHERE occupants.id = '2'", (status, timestamp))
			connection.commit()
	
	morganResult = bluetooth.lookup_name('9C:65:B0:8B:16:A0', timeout=5)
	ts = time.time()
	timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
	if (morganResult != None):
		sshtunnel.SSH_TIMEOUT = 30.0
		sshtunnel.TUNNEL_TIMEOUT = 30.0
		with sshtunnel.SSHTunnelForwarder(
			('ssh.pythonanywhere.com'),
			ssh_username='xxx', ssh_password='xxx',
			remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
		) as tunnel:
			connection = mysql.connector.connect(
				user='xxx', password='xxx',
				host='127.0.0.1', port=tunnel.local_bind_port,
				database='xxx$hivedashboard',
		)
			cursor = connection.cursor()
			status = "In"
			cursor.execute("UPDATE occupants SET status = %s, lastin = %s  WHERE occupants.id = '3'", (status, timestamp))
			connection.commit()
	    	score = score + 1
	else:
		sshtunnel.SSH_TIMEOUT = 30.0
		sshtunnel.TUNNEL_TIMEOUT = 30.0
		with sshtunnel.SSHTunnelForwarder(
			('ssh.pythonanywhere.com'),
			ssh_username='xxx', ssh_password='xxx',
			remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
		) as tunnel:
			connection = mysql.connector.connect(
				user='xxx', password='xxx',
				host='127.0.0.1', port=tunnel.local_bind_port,
				database='xxx$hivedashboard',
		)
			cursor = connection.cursor()
			status = "Out"
			cursor.execute("UPDATE occupants SET status = %s, lastout = %s  WHERE occupants.id = '3'", (status, timestamp))
			connection.commit()
	
	connorResult = bluetooth.lookup_name('18:83:31:8D:01:04', timeout=5)
	ts = time.time()
	timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
	if (connorResult != None):
		sshtunnel.SSH_TIMEOUT = 30.0
		sshtunnel.TUNNEL_TIMEOUT = 30.0
		with sshtunnel.SSHTunnelForwarder(
			('ssh.pythonanywhere.com'),
			ssh_username='xxx', ssh_password='xxx',
			remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
		) as tunnel:
			connection = mysql.connector.connect(
				user='xxx', password='xxx',
				host='127.0.0.1', port=tunnel.local_bind_port,
				database='xxx$hivedashboard',
		)
			cursor = connection.cursor()
			status = "In"
			cursor.execute("UPDATE occupants SET status = %s, lastin = %s  WHERE occupants.id = '4'", (status, timestamp))
			connection.commit()
	    	score = score + 1
	else:
	   	sshtunnel.SSH_TIMEOUT = 30.0
		sshtunnel.TUNNEL_TIMEOUT = 30.0
		with sshtunnel.SSHTunnelForwarder(
			('ssh.pythonanywhere.com'),
			ssh_username='xxx', ssh_password='xxx',
			remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
		) as tunnel:
			connection = mysql.connector.connect(
				user='xxx', password='xxx',
				host='127.0.0.1', port=tunnel.local_bind_port,
				database='xxx$hivedashboard',
		)
			cursor = connection.cursor()
			status = "Out"
			cursor.execute("UPDATE occupants SET status = %s, lastout = %s  WHERE occupants.id = '4'", (status, timestamp))
			connection.commit()
	sshtunnel.SSH_TIMEOUT = 30.0
	sshtunnel.TUNNEL_TIMEOUT = 30.0
	with sshtunnel.SSHTunnelForwarder(
		('ssh.pythonanywhere.com'),
		ssh_username='xxx', ssh_password='xxx',
		remote_bind_address=('xxx.mysql.pythonanywhere-services.com', 3306)
	) as tunnel:
		connection = mysql.connector.connect(
			user='xxx', password='xxx',
			host='127.0.0.1', port=tunnel.local_bind_port,
			database='xxx$hivedashboard',
	)
		cursor1 = connection.cursor()
		cursor1.execute("UPDATE Heating SET Score = %s WHERE Heating.id = '1'", (score,))
		connection.commit()

#scanner = Scanner().withDelegate(ScanDelegate())
#devices = scanner.scan(10.0)


#return  'OK'
The 'class' bit works fine and does exactly what I'd expect it to do.

The 'others' bit doesn't get run.

The problem is that I need the 2 'scanner' lines to run before the 'others' bit or I end up with an error:

Code: Select all

bluepy.btle.BTLEDisconnectError: Device disconnected
Could someone point me in the right direction to get the blocks in the right order, please. I'm probably running more connections, etc, to the DB than I need as well so any steer on that would be gratefully received.

Cheers
Andy

User avatar
MrYsLab
Posts: 441
Joined: Mon Dec 15, 2014 7:14 pm
Location: Noo Joysey, USA

Re: Struggling with structure of classes and functions

Sun Nov 25, 2018 12:14 am

I can't help with the DB code, but to get things in the correct order, couldn't you create a new class that contains "others" as a method.

Here is what I am thinking:

Code: Select all

class Addition:
    def __init__(self):
        scanner = Scanner().withDelegate(ScanDelegate())
        devices = scanner.scan(10.0)
        // is a short delay necessary for the scanning to complete?
        self.others()
        
    def others(self):
        // the orginal others function code goes here
        
add = Addtion()
This new class will instantiate the ScanDelegate class, and then call the others method.

oldjake
Posts: 90
Joined: Fri Aug 03, 2018 12:39 pm

Re: Struggling with structure of classes and functions

Mon Nov 26, 2018 8:43 am

Thanks for that. I did some reading on classes and functions and I think the penny is dropping. The way I'm seeing it is that a class doesn't get run unless it gets called so something like (in pretend code):

Code: Select all

main prog
    class classOne():
        Do some stuff

    class classTwo():
        Dome some more stuff

run classOne
run classTwo
So in my case, I'd have the main class that uses Bluepy and then another class for the 'others'. Then in my main code I need something to run both classes.

Have I understood that correctly?

Cheers
Andy

User avatar
topguy
Posts: 6791
Joined: Tue Oct 09, 2012 11:46 am
Location: Trondheim, Norway

Re: Struggling with structure of classes and functions

Mon Nov 26, 2018 1:49 pm

I think the penny is still a couple of feet of the floor.

A class is never "run".

A class named "Human" defines what objects of type "Human" can have as parameters and what they can do (methods)
So the class Human can define that Humans should have parameters like "name", "height", "weight" and can do stuff like run(), jump() and sit().

But notthing happens until you create a Human object "bob", "bob" has the parameters "Robert", "167cm" and "67kg".
Then you can do "bob.jump()" and the Human with name "Robert" jumps..

Code: Select all


class Human:
   String name
   Int height
   Int weight
   jump(Int howhi )  { print name "jumps" howhi "cm" }
   run() { print name "runs" }
   sit() { print name "sits" }

main()
   Human bob:
   bob.name = "Robert"
   bob.height = 167
   bob.weight = 67
   bob.jump( 100 )
And the teoretical result from this program is "Robert jumps 100 cm"

Return to “Python”