Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
Hand tools and fabrication machines | ||||||
|
This entire project is built as part of another work project trying to learn Pycom SiPy and Sigfox. I used the ADXL345 accelerometer to detect different movements like a knock on a door or the movement of a piston. The system is built with the potential of using a powerbank or other battery to power the system and make it independent from main or other wiring.
Getting startedI suggest looking into this guide, https://www.hackster.io/bucknalla/sending-a-sigfox-message-with-micropython-52b2a1, to learn the basics of how to use the Pycom SiPy. The biggest job in this project was to write the driver for the ADXL345. The entire code is placed in the code section. It should be commented fairly well (tried to make it explanatory).
I use the Pycom SiPy with the expansion board. The connections/schematics are as follows (I chose to also write down the color of the wires used):
- ADXL —> SiPy
- GND —> GND (black)
- Vin —> 3.3v (red)
- SDA —> P9 / G16 (blue)
- SCL —> P10 / G17 (yellow)
ADXL345 driver for Pycom SiPy
MicroPython###
### Made with inspiration from: https://github.com/pimoroni/adxl345-python/blob/master/adxl345.py
### This is an I2C driver for the Adafruit ADXL345 Accelerometer: https://learn.adafruit.com/adxl345-digital-accelerometer?view=all
### At the moment it is possible to set the data range going from 2G to 16G
### Optimizations that could be done:
### - Write the binaries for the other output data rates
### - Write a calibration part
### - Make it possible to call the initiate the changes to data range and
### bandwidth from main program
#The address of the ADXL345 given in the datasheet
ADXL345_ADDR = 0x53
#The bytes for making the ADXL345 send at 100Hz output data rate
BW_RATE_100HZ = 0x0B
#The address for making changes to POWER_CTL
POWER_CTL = 0x2D
#The byte "code" for starting the measurements
MEASURE = 0x08
#The address for changing the DATA_FORMAT. This is used together with the ranges
DATA_FORMAT = 0x31
#The address where the measurement data starts from. Each axis has two bytes for the given value
AXES_DATA = 0x32
#The address for accessing and setting the bandwidth rate
BW_RATE = 0x2C
#Decide the range of measurements ie the precision. Possible options
#2G
RANGE_2G = 0x08
#4G
RANGE_4G = 0x09
#8G
RANGE_8G = 0x2A
#16G
RANGE_16G = 0x0F
SCALE_MULTIPLIER = 0.004
#Standard gravity constant for going from G-force to m/s^2
EARTH_GRAVITY_MS2 = 9.80665
class ADXL345:
def __init__(self, i2c):
self.i2c = i2c
self.addr = ADXL345_ADDR
self.setBandwidthRate(BW_RATE_100HZ)
self.setRange(RANGE_8G)
self.enableMeasurement()
def enableMeasurement(self):
self.i2c.writeto_mem(self.addr, POWER_CTL, bytes([MEASURE]))
def setBandwidthRate(self, rate_flag):
self.i2c.writeto_mem(self.addr, BW_RATE, bytes([rate_flag]))
def setRange(self, range_flag):
self.i2c.writeto_mem(self.addr, DATA_FORMAT, bytes([range_flag]))
def getAxes(self, gforce = False):
bytes = self.i2c.readfrom_mem(self.addr, AXES_DATA, 6)
x = bytes[0] | (bytes[1] << 8)
if(x & (1 << 16 - 1)):
x = x - (1<<16)
y = bytes[2] | (bytes[3] << 8)
if(y & (1 << 16 - 1)):
y = y - (1<<16)
z = bytes[4] | (bytes[5] << 8 )
if(z & (1 << 16 - 1)):
z = z - (1<<16)
x = x * SCALE_MULTIPLIER
y = y * SCALE_MULTIPLIER
z = z * SCALE_MULTIPLIER
if gforce == False:
x = x * EARTH_GRAVITY_MS2
y = y * EARTH_GRAVITY_MS2
z = z * EARTH_GRAVITY_MS2
x = round(x,4)
y = round(y,4)
z = round(z,4)
return {"x": x, "y": y, "z": z}
import time
import machine
import pycom
import adxl345
pycom.heartbeat(False)
#Set the I2C and Pin to machine. so the code from before still works
I2C = machine.I2C
Pin = machine.Pin
Timer = machine.Timer
chrono = Timer.Chrono()
#initialize the I2C bus
i2c = I2C(0, I2C.MASTER, baudrate=100000)
value = 0
time.sleep_ms(1000)
setRTCLocalTime()
savedTime = time.localtime()
counter = 1
timeThreshold = 600
#threshold is measued in g
threshold = 1
stateMotion = False
hitCount = 0
stateSigfox = False
measureCounter = 500
measureThreshold = 500
#Set this to false to turn off indication lights
lightVar = True
if lightVar == True:
print('Turn lights on')
chrono.start()
print('Starting the loop')
while True:
data = adxl345.ADXL345(i2c)
axes = data.getAxes(True)
x = axes['x']
x = abs(x)
y = axes['y']
y = abs(y)
z = axes['z']
z = abs(z)
measureCounter += 1
if (threshold <= x) or (threshold <= y) or (threshold <= z):
if measureThreshold <= measureCounter:
stateMotion = True
hitCount = hitCount + 1
print('I have been hitten')
print('My count is ')
print(hitCount)
measureCounter = 0
#This function checks if it is allowed to send a message via SigFox (one every 10 minutes)
if timeThreshold <= chrono.read():
stateSigfox = True
chrono.stop()
#This function first checks if the state of motion has changed, ie. have the acc crossed the threshold
if stateMotion == True:
#Then it checks if it is allowed to send a message
if stateSigfox == True:
#Send shit to sigfox
print('I am going to send this hit count ')
print(hitCount)
#Send the bitcount to SigFox
hitCount = str(hitCount)
s.send("Hit" + hitCount)
counter = 1
stateSigfox = False
stateMotion = False
hitCount = 0
chrono.reset()
chrono.start()
if lightVar == True:
if (stateMotion == True) and (stateSigfox != True):
#There has been motion but SigFox is not allowed to send messages
pycom.rgbled(0x007f00) #green
elif (stateMotion != True) and (stateSigfox == True):
#Sigfox can send message but there has been no motion
pycom.rgbled(0x7f7f00) #yellow
elif (stateMotion != True) and (stateSigfox != True):
#Neither motion has occured or SigFox can send messages
pycom.rgbled(0x7f0000) #red
known_nets = [('ssid', 'pass')]
import machine
import os
from network import Sigfox
import binascii
import socket
import time
#Initiates Sigfox communication
sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ1) #RCZ1/RCZ3 Europe / Japan / Korea
#initiates the UART (USB) connection
uart = machine.UART(0, 115200)
os.dupterm(uart)
#WiFi setup
if machine.reset_cause() != machine.SOFT_RESET: #needed to avoid losing connection after a soft reboot
from network import WLAN
wl = WLAN()
# save the default ssid and auth
original_ssid = wl.ssid()
original_auth = wl.auth()
wl.mode(WLAN.STA)
available_nets = wl.scan()
nets = frozenset([e.ssid for e in available_nets])
known_nets_names = frozenset([e[0] for e in known_nets])
net_to_use = list(nets & known_nets_names)
try:
net_to_use = net_to_use[0]
pwd = dict(known_nets) [net_to_use]
sec = [e.sec for e in available_nets if e.ssid == net_to_use][0]
wl.connect(net_to_use, (sec, pwd), timeout=10000)
except:
wl.init(mode=WLAN.AP, ssid=original_ssid, auth=original_auth, channel=6, antenna=WLAN.INT_ANT)
#SigFox setup
#Create a Sigfox socket
s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
#Make the socket blocking
s.setblocking(True)
#Configure it as uplink only
s.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False)
#Time setup
def setRTCLocalTime():
rtc = machine.RTC()
rtc.ntp_sync("pool.ntp.org")
time.sleep_ms(750)
print('\nRTC Set from NTP to UTC', rtc.now())
time.timezone(3600) #GMT + 1 Copenhagen, Amsterdan, Paris
print('Adjusted from UTC to GMT+1', time.localtime(), '\n')
Comments