#!/usr/bin/perl -w
use strict;
use DBI;
my $dock_status;
my $this_rack_num = 1;
# get initial dock status from db
my $orig_dock_status = initialize_rack($this_rack_num);
print "\n\norig_dock_status: $orig_dock_status\n\n";
#my $i = 0;
# inifinitely scan the 1-wire bus
while(1)
{
# get ids on the 1-wire net bus
my $bus_ids = get_all_bus_ids();
# print "bus_ids: $bus_ids\n";
# if the dock has a vehicle in it
if($bus_ids =~ /([A-Z0-9]{16})-([A-Z0-9]{16})-/)
{
#set the dock status to the vehicle_id
$dock_status = $1;
print "dock: $2 dock_status: $dock_status (vehicle_id)\n";
}
# else if the dock is empty
elsif($bus_ids =~ /([A-Z0-9]{16})-/)
{
# set the dock_status to empty
$dock_status = "empty";
print "Dock is empty\n";
}
# if a vehicle has been returned. ie:
# if the original dock status has changed and the dock has a vehicle
if(($orig_dock_status ne $dock_status) && ($dock_status ne "empty"))
{
#for right now the code only deals with one dock (1)
my $dock_num = 1;
print "vehicle returned. vehicle_id: $dock_status\n";
# update the orig_dock_status for comparison next time through the loop
$orig_dock_status = $dock_status;
# We've figured out $dock_status is a vehicle_id
# now convert the long vehicle_id into a short friendly vehicle_num
my $vehicle_num = convert_vehicle_id_to_num($dock_status);
# Figure out who had the vehicle
my $matched_user_id = match_user_to_vehicle($vehicle_num);
my $full_name = match_user_id_to_user_name($matched_user_id);
print "returned by: $full_name\n";
# Set vehicle.availability back to available
update_vehicle_availability($vehicle_num, "available");
# update the dock.dock_status in the database to reflect the checked in vehicle
# yikes... for right now dock is hard coded.
update_dock_status($dock_num, $this_rack_num, $vehicle_num);
# print "+++vehicle_num: $vehicle_num+++\n";
# Update events table: date_time, action, user_id, rack_id, dock_id,
# vehicle_id
#action, user_id, rack_num, dock_num, vehicle_num, [elapsed_time]
add_events_entry("sign_in",$matched_user_id,$this_rack_num,$dock_num,$vehicle_num);
# check if vehicle is overdue. If vehicle is overdue
# Take appropriate action
# haven't decided what this is yet, but if any action is going to be
# taken it needs to be somewhat sophisiticated. For example, if
# it's the first offense and the bike is only a few minutes late,
# perhaps just send an email to the person urging them to return the
# vehicle in a more timely manner. If it's a 3rd offense and the
# vehicle is an hour late, send a charge to their account. There
# needs to be a method for storing, retrieving, and weighing the
# history of each individual. We could possible have "karma"
# stored in the user database and as that number reaches certain
# thresholds different actions are taken. Users could start at 0.
# Certain infractions add predetermined number of points to their
# karma. If they finally reach 100, for example, their account
# would be set to disabled and they would no longer be able to use
# the system. I think the Amsterdam program also rewarded people if
# they brought vehicles from a heavily loaded rack to an empty rack.
# Users could earn good karma for this and perhaps a very small
# amount of karma could be earned if they return the vehicle quickly
# to allow others to use the bikes
# print " orig_dock_status: $dock_status\n\n";
}
# if a vehicle has been checked out
# check out code should already know about it
elsif(($orig_dock_status ne $dock_status) && ($dock_status eq "empty"))
{
print "orig_dock_status: $orig_dock_status dock_status: $dock_status\n";
print "a bike has been removed from the dock\n";
# update the orig_dock_status for comparison next time through the loop
$orig_dock_status = "empty";
}
# if nothing has changed since the last time through
else
{
# print "nothing changed ";
# print "dock_status: $dock_status\n\n";
}
`sleep 2`;
# $i++;
}
#my @binky;
#my $dock_id;
#my $vehicle_id;
#my %initial_rack_ids = initialize_rack();
#print "bla: $bus_ids";
#@binky = clean_rack_ids($bus_ids);
#print "dock_id: $binky[1]\n";
#print "vehicle_id: $binky[0]\n";
#while (($dock_id,$vehicle_id) = each(%initial_rack_ids))
#{
# print "dock: $dock_id\nvehicle: $vehicle_id\n";
#}
################################################################################
# Function: get_all_bus_ids
# Description: calls an external program which returns all ids on the 1-wire
# net bus
# Arguments: none
# Returns: string raw ids (each id is separated by a - (there is a - at the
# end as well)
# Status: 80% (clean up. Also abstract the port to read from)
################################################################################
sub get_all_bus_ids
{
# get all the ids and store the raw string to $all_bus_ids
# This assumes that the 1-wire net reader is connected to /dev/ttyS1 and
# that get_ids is in the same directory that this program is being run from
my $all_bus_ids = `./get_ids \/dev\/ttyS1`;
return $all_bus_ids;
}
################################################################################
# Function: clean_rack_ids
# Description: takes the id dump for the bus and separates out into
# vehicle_id/dock_id paired hash
# Arguments: string raw_rack_ids
# Returns: hash cleaned_rack_ids
# Status: 5%
################################################################################
sub clean_rack_ids
{
my $raw_rack_ids = $_[0];
my @split_rack_ids;
# remove the newline and the ending -
chop $raw_rack_ids;
chop $raw_rack_ids;
@split_rack_ids = split /-/, $raw_rack_ids;
#print "dock_id: $split_rack_ids[1]\n";
#print "vehicle_id: $split_rack_ids[0]\n";
return @split_rack_ids;
}
################################################################################
# Function: initialize_rack()
# Description: Before we get id's from the rack, the values need to be seeded
# from the database. This function gets the status of each dock
# from the dock table to get a values to be used for comparison
# Arguments: int rack_id
# Returns: hash - vehicle_id/dock_id pair?
# Prerequisite: none
# Status: 3% Need to figure out format of returned data and whole lot of other
# stuff. Returned value is hard coded until I better understand what
# is going on.
################################################################################
sub initialize_rack
{
my $rack_num = $_[0];
# temporary hack
my $dock_num = 1;
my %initial_rack_ids;
# my %initial_rack_ids = ('9B000001A8CB4209','58000006377AD201');
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
#build query - find dock_ids matching vehicle_ids
# my $query = "SELECT dock\.dock_id, vehicle\.vehicle_id FROM dock, vehicle WHERE dock\.dock_status = vehicle\.vehicle_num AND dock\.rack_id='$rack_id'";
#this query only gets the status of rack 1 dock 1. This obviously needs major modifications
$query = "SELECT dock_status FROM dock WHERE dock_num='1'";
# print $query;
#execute query
$sth = $dbh->prepare($query);
$sth->execute();
#fetch results
my $initial_dock_status = $sth->fetchrow_array();
# return %initial_rack_ids;
return $initial_dock_status;
}
################################################################################
# Function: convert_vehicle_id_to_num()
# Description: converts long vehicle_id's to user friendly vehicle_num
# Arguments: string vehicle_id
# Returns: int vehicle_num
# Prerequisite: none
# Status: 5%
################################################################################
sub convert_vehicle_id_to_num
{
my $vehicle_id = $_[0];
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
# create query
$query = "SELECT vehicle_num FROM vehicle WHERE vehicle_id='$vehicle_id'";
# print $query;
#execute query
$sth = $dbh->prepare($query);
$sth->execute();
#fetch results
my $vehicle_num = $sth->fetchrow_array();
return $vehicle_num;
}
################################################################################
# Function: match_user_to_vehicle
# Description: checks the vehicle.availability field to get a user_id of the
# person who has the vehicle
# Arguments: string vehicle_id
# Returns: int matched_user_id
# Prerequisite: this function is intended to be used to check vehicles which
# have their availability set to the user_id of the person who
# has signed it out.
# Status: 5%
################################################################################
sub match_user_to_vehicle
{
my $vehicle_num = $_[0];
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
# create query
$query = "SELECT availability FROM vehicle WHERE vehicle_num='$vehicle_num'";
# print $query;
#execute query
$sth = $dbh->prepare($query);
$sth->execute();
#fetch results
my $matched_user_id = $sth->fetchrow_array();
return $matched_user_id;
}
################################################################################
# Function: match_user_id_to_user_name
# Description: uses the user_id to get and return the users Name.
# Arguments: string user_id
# Returns: string full_name
# Prerequisite: none
# Status: 5%
################################################################################
sub match_user_id_to_user_name
{
my $user_id = $_[0];
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
# create query
$query = "SELECT first_name, last_name FROM user WHERE user_id='$user_id'";
# print $query;
#execute query
$sth = $dbh->prepare($query);
$sth->execute();
#fetch results
my @results = $sth->fetchrow_array();
my $full_name = $results[0] . " " . $results[1];
return $full_name;
}
### NOTE: This function already exists in check out code ###
################################################################################
# Function: update_dock_status
# Description: updates status of dock_status in the dock database
# Arguments: int dock_num, int rack_num, string dock_status (empty or vehicle_id)
# Returns: bool - true on success
# Status: 90% (functional needs cleanup)
################################################################################
sub update_dock_status
{
my $dock_num = $_[0];
my $rack_num = $_[1];
my $dock_status = $_[2];
my $rows;
my $outcome;
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
$query = "UPDATE dock SET dock_status='$dock_status' WHERE rack_num='$rack_num' AND dock_num='$dock_num'";
# print "\nquery: $query\n";
$rows = $dbh->do ($query);
$dbh->disconnect();
if(!defined($rows)) #if there was an error
{
$outcome = "0"; #return false
}
elsif($rows == "0E0") #if no rows were affected
{
$outcome = "0";
# print "\ngot into the 0E0 Statement\n";
}
else
{
$outcome = "1"; # return true
}
return $outcome;
}
### NOTE: This function already exists in check out code ###
### I changed vehicle_id's to vehicle_num but not in check out code merge!!! ###
################################################################################
# Function: update_vehicle_availability
# Description: updates availability of specified vehicle
# Arguments: vehicle_id, availability (available, unavailable, or user_id)
# Returns: bool - 1 on success, 0 on failure
# Status: 90% (functional needs cleanup)
################################################################################
sub update_vehicle_availability
{
my $vehicle_num = $_[0];
my $availability = $_[1];
my $outcome;
my $rows;
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
#build query
$query = "UPDATE vehicle SET availability='$availability' WHERE vehicle_num='$vehicle_num'";
# print "\nupdate_vehicle_availability: $query\n";
#run query
$rows = $dbh->do ($query);
$dbh->disconnect();
# print "\nrows: $rows\n";
if(!defined($rows)) #if there was an error
{
$outcome = "0"; #return false
# print "\nnot defined\n";
}
elsif($rows == "0E0") #if no rows were affected
{
$outcome = "0";
# print "\ngot into the 0E0 Statement\n";
}
else
{
$outcome = "1"; # return true
}
return $outcome;
}
### NOTE: This function already exists in check out code ###
### I modified the sql statement since the time_interval is never used here
### have to generalize to check to see if the variable is present or not when
### building the statement
################################################################################
# Function: add_events_entry
# Description: Gathers all the variables and makes an entry in the events table
# Arguments: action, user_id, rack_num, dock_num, vehicle_num, [elapsed_time]
# Returns:
# Status: 75% (quasi-functional need to deal with the issue of optional arguments)
################################################################################
sub add_events_entry
{
#arguments
my $action = $_[0];
my $user_id = $_[1];
my $rack_num = $_[2];
my $dock_num = $_[3];
my $vehicle_num = $_[4];
# my $time_interval = $_[5];
my $rows;
my $outcome;
my ($dsn) = "DBI:mysql:bike_program:localhost";
my ($user_name) = "bike";
my ($password) = "5xMts6";
my ($query);
my ($dbh, $sth);
my (@ary);
# connect to database
$dbh = DBI->connect ($dsn, $user_name, $password, { RaiseError => 1});
$query = "INSERT INTO events SET action='$action', user_id='$user_id', rack_num='$rack_num', dock_num='$dock_num', vehicle_num='$vehicle_num'";
# print "\nquery: $query\n";
$rows = $dbh->do ($query);
$dbh->disconnect();
if(!defined($rows)) #if there was an error
{
$outcome = "0"; #return false
}
elsif($rows == "0E0") #if no rows were affected
{
$outcome = "0";
# print "\ngot into the 0E0 Statement\n";
}
else
{
$outcome = "1"; # return true
}
return $outcome;
}