Nerds eh? MUTE!Nerds
#!/bin/bash
# The script either detects or modifies the radio's mute setting.
usage() {
echo ""
echo "USAGE: $(basename $0) [on/off]"
echo ""
exit 1
}
TRIES=0
MAXTRIES=3
DEBUG=false
DELAY=1.1
MUTEID=99
MUTEWANTED=$(echo $1 | tr '[:lower:]' '[:upper:]')
[ "$MUTEWANTED" == "" ] && MUTEWANTED=XX
[ "$MUTEWANTED" == "ON" ] && MUTEWANTED=03
[ "$MUTEWANTED" == "OFF" ] && MUTEWANTED=00
[ "$MUTEWANTED" != "00" ] && [ "$MUTEWANTED" != "03" ] && [ "$MUTEWANTED" != "XX" ] && usage
read_error() {
echo "FAILURE: Could not read the mute status."
echo ""
# Exit with a failure result code
exit 1
}
write_error() {
echo "FAILURE: Could not change the mute status."
echo ""
# Exit with a failure result code
exit 1
}
request_mute () {
# Collect fourth byte of message ID $25D on CAN-C.
# After $DELAY seconds, stop collecting.
COMMAND="timeout -s 1 $DELAY /usr/bin/candump -L can1,025D:0FFF"
# Only collect messages which are a direct response to our own query.
# All other messages will be ignored.
RESPONSE=$( $COMMAND | cut -d# -f2 | cut -c7-8 | tail -1)
}
# MAIN PROGRAM LOOP BEGINS HERE ------------------------------------------
# Read the mute status. If it isn't what we want,
# hit the mute button!
while [ $MUTEID != $MUTEWANTED ]
do
# See what our mute status is (no actual request, just listening)
request_mute
# If no response was found, try again.
if [ "$RESPONSE" == "" ] ; then
DELAY=1.6
/home/pi/bin/wake
request_mute
fi
# If no response was found, try again.
if [ "$RESPONSE" == "" ] ; then
DELAY=2.2
request_mute
# If no response AGAIN, then exit with an error.
if [ "$RESPONSE" == "" ] ; then read_error; fi
fi
MUTEID=$RESPONSE
[ "$MUTEWANTED" == "XX" ] && {
[ "$MUTEID" == "03" ] && { echo ON; exit 0; }
[ "$MUTEID" == "00" ] && { echo OFF; exit 0; }
echo UNKNOWN ; exit 1
}
# If the mute status isn't what we want, hit the mute toggle button.
[ "$DEBUG" == "true" ] && echo MUTEID: $MUTEID MUTEWANTED: $MUTEWANTED
[ "$MUTEID" != "$MUTEWANTED" ] && {
# It isn't what we want. We're hitting the MUTE toggle button.
[ "$DEBUG" == "true" ] && echo TOGGLING MUTE
cansend can0 2D3#0700010000000000 ; sleep 0.21
}
# We're going to try up to FIVE times to change the mute status.
# After that, exit with an error.
TRIES=$(( $TRIES + 1 ))
[ "$TRIES" -gt $MAXTRIES ] && write_error
done
# A clean exit. Either we reported a value, made a change, or was requested
# to make a change but no change was necessary.
exit 0
Right now, we're reverse engineering CAN bus traffic and we're trying to figure out the brave new world of Unified Diagnostic Services. Those aren't the fun things. Those are two major pieces of homework which allows us to make fun things. That aside, we've started making progress towards our own projects.It was so dense that I just skipped over the remaining 18 pages. What all have you been able to do? Sounds like maybe you are just using a raspberry pit to control everything? Pretty neat stuff.
I just now noticed how much of the underlying technology was given away by one of their product images at Amazon.New Project? RGB *Smart* Halo Lights
I think I may have walked into a new project.
This has been on my mind as well. small can devices that can be placed anywhere in the vehicle. for lights, relays, etc... Just use can addresses not used by the jeep and it's all good without the hassle of running wires..EDIT: If I only had the time to burn, I'd create a CAN-aware WS2811 controller. Given the opportunity to spread RGB devices around a vehicle, that actually starts to make some sense.
Yes! And it works out two different ways. First, you can directly address them and tell multiple units at once (in a synchronized manner) what pattern to start playing. Second, you could have another set of commands that instructs these CAN devices to themselves listen to to existing CAN traffic for specific messages that they can take their own cues from.This has been on my mind as well. small can devices that can be placed anywhere in the vehicle. for lights, relays, etc... Just use can addresses not used by the jeep and it's all good without the hassle of running wires..
I'd suggest to avoid these canned controllers. heh, canned. lol...PS: I went ahead and bought a SP105E (bluetooth controller) and a SP108E (Wi-Fi controller) as an alternative means to control those RGB LED headlights. I've already found one project which manages to control the SP108E over an ad-hoc Wi-Fi network. But I'd feel more secure with the Wi-Fi transmitter powered down.
#!/bin/bash
# This script reads or sets the HVAC fan speed.
usage() {
echo ""
echo "USAGE: $(basename $0) [speed]"
echo " When setting values: 01 (low) through 07 (max)"
echo " When reading values: 00 (off), 01 (low) through 07 (max)"
echo " "
exit 1
}
TRIES=0
MAXTRIES=5
DEBUG=false
DELAY=1.1
SPEEDID=99
SPEEDWANTED="$1"
SHOWUSAGE=1
[ $SPEEDWANTED -gt 0 ] 2>/dev/null && [ $SPEEDWANTED -lt 8 ] 2>/dev/null && SHOWUSAGE=0
[ "$SPEEDWANTED" == "" ] && { SPEEDWANTED="XX"; SHOWUSAGE=0; }
[ $SHOWUSAGE -eq 1 ] && usage
read_error() {
echo "FAILURE: Could not read a valid fan speed message."
echo ""
# Exit with a failure result code
exit 1
}
write_error() {
echo "FAILURE: Could not change the fan speed to the desired value."
echo ""
# Exit with a failure result code
exit 1
}
request_fan_speed () {
# Collect fan speed from message ID $2B1 on CAN-C
# This message repeats one time per second.
# After $DELAY seconds, stop collecting.
COMMAND="timeout -s 1 $DELAY /usr/bin/candump -L can1,02B1:0FFF"
# Only collect messages which are a direct response to our own query.
# All other messages will be ignored.
RESPONSE=$( $COMMAND | cut -d# -f2 | cut -c1-2 | tail -1)
}
# MAIN PROGRAM LOOP BEGINS HERE ------------------------------------------
# Read the HVAC fan speed. If it isn't what we want, hit the "FAN +" or
# the "FAN -" as many times as neeeded. Lather, rinse, repeat. Delays are
# introduced into each of these loops in order to avoid hysteresis.
while [ $SPEEDID != $SPEEDWANTED ]
do
# Read the HVAC fan speed from the CAN bus
request_fan_speed
# If no response was found, send a wakeup packet. Try again.
if [ "$RESPONSE" == "" ] ; then
DELAY=1.1
/home/pi/bin/wake ; sleep 0.5
request_fan_speed
fi
# If no response was found, send a wakeup packet. Try again.
if [ "$RESPONSE" == "" ] ; then
DELAY=1.8
/home/pi/bin/wake
request_fan_speed
# If no response AGAIN, then exit with an error.
if [ "$RESPONSE" == "" ] ; then read_error; fi
fi
SPEEDID=$( printf "%d" 0x$RESPONSE )
# A speed of "127" means offline, so we'll treat it as fan speed 0.
[ $SPEEDID -eq 127 ] && SPEEDID=0
[ $SPEEDID -gt 7 ] && read_error
# If the user supplied no arguments, print the fan speed and exit.
[ "$SPEEDWANTED" == "XX" ] && {
echo $SPEEDID
exit 0
}
# If the current HVAC fan speed isn't what we want, then hit the
# appropriate fan speed buttons to increase or decrease it.
[ "$DEBUG" == "true" ] && echo SPEED: $SPEEDID DESIRED: $SPEEDWANTED
[ "$SPEEDID" -lt "$SPEEDWANTED" ] && {
for i in $( seq $SPEEDID $(( $SPEEDWANTED -1 )) )
do
# Increase the fan speed
# Use a larger delay to compensate for fan spin-up time
[ "$DEBUG" == "true" ] && echo REQUESTING FAN SPEED INCREASE
cansend can0 273#0000050000000000; sleep 0.73
done
# exit 0
}
[ "$SPEEDID" -gt "$SPEEDWANTED" ] && {
for i in $( seq $SPEEDWANTED $(( $SPEEDID -1 )) )
do
# Decrease the fan speed
# Use a short delay because fans wind-down quickly.
[ "$DEBUG" == "true" ] && echo REQUESTING FAN SPEED DECREASE
cansend can0 273#00000A0000000000; sleep 0.23
done
# exit 0
}
[ "$SPEEDID" -eq "$SPEEDWANTED" ] && exit 0
# We're going to try up to FIVE times to change the HVAC fan speed.
# After that, exit with an error.
TRIES=$(( $TRIES + 1 ))
[ "$TRIES" -gt $MAXTRIES ] && write_error
done
# A clean exit. Either we reported a value, made a change, or was requested
# to make a change but no change was necessary.
exit 0
#!/bin/bash
touch /tmp/remote
# Do some quick WiFi Tuning (might produce errors, that's okay)
iwconfig wlan0 rate auto
iwconfig wlan0 rts 2304
iwconfig wlan0 frag 2304
# Monitors for *remote* door lock/unlock commands and uses
# those to disable/enable the Raspberry Pi's WiFi transmitter.
#
# Locked = WiFi Off (secure)
# Unlocked = WiFi On (less secure)
# Tunable variables:
# Name for the CAN-IHS interface (can0, can1, vcan0, etc)
CANIHS=can0
WIFIDEV=wlan0
DEBUG=false # Values: true,false,raw
LOCKED=0
LASTREMOTE="1C0#FFFFFFFFFFFF"
sleep 5
candump -L $CANIHS,01C0:0FFFF | while read time bus REMOTE
do
[ $DEBUG == "raw" ] && echo CAN-IHS data: $REMOTE
HEADER="TIME : $time $( date )\nDATA : $REMOTE"
# LOCK COMMAND: WIFI TURNED OFF (SECURED)
if [ "$REMOTE" == "1C0#210000900000" ] ; then
if [ "$REMOTE" != "$LASTREMOTE" ] ; then
[ $DEBUG == "true" ] && echo -e "$HEADER"
[ $DEBUG == "true" ] && echo "EVENT : KEYFOB LOCK COMMAND RECEIVED"
[ $DEBUG == "true" ] && echo "ACTION: NONE"
[ $DEBUG == "true" ] && echo ""
fi
fi
# 1ST UNLOCK COMMAND: NO ACTION TAKEN
if [ $REMOTE == "1C0#230000900000" ] ; then
if [ "$REMOTE" != "$LASTREMOTE" ] ; then
[ $DEBUG == "true" ] && echo -e "$HEADER"
[ $DEBUG == "true" ] && echo "EVENT : KEYFOB 1ST UNLOCK COMMAND RECEIVED"
[ $DEBUG == "true" ] && echo "ACTION: NONE"
[ $DEBUG == "true" ] && echo ""
fi
fi
# 2ND UNLOCK COMMAND: WIFI TURNED ON (LESS SECURED)
if [ $REMOTE == "1C0#240000900000" ] ; then
if [ "$REMOTE" != "$LASTREMOTE" ] ; then
[ $DEBUG == "true" ] && echo -e "$HEADER"
[ $DEBUG == "true" ] && echo "EVENT : KEYFOB 2ND UNLOCK COMMAND RECEIVED"
# Flip between locked (LOCKED=1) and unlocked (LOCKED=0)
LOCKED=$(( ! $LOCKED ))
[ $LOCKED -eq 0 ] && {
# ENABLING WIFI TRANSMITTER
# All commands appear to be necessary even if they return errors.
# Use extreme care when editing the following section.
echo $(date) REMOTE: Turning on Wi-Fi Device
iwconfig $WIFIDEV txpower on
sleep 5
iwconfig $WIFIDEV txpower auto
sleep 2
ifconfig $WIFIDEV up
}
[ $LOCKED -eq 1 ] && {
# DISABLING WIFI TRANSMITTER
echo $(date) REMOTE: Turning off Wi-Fi Device
ifconfig $WIFIDEV down
sleep 2
iwconfig $WIFIDEV txpower off
}
[ $DEBUG == "true" ] && echo ""
fi
fi
# IDLE (NO COMMANDS): NO ACTION
if [ $REMOTE == "1C0#000000800000" ] ; then
if [ "$REMOTE" != "$LASTREMOTE" ] ; then
[ $DEBUG == "true" ] && echo -e "$HEADER"
[ $DEBUG == "true" ] && echo "EVENT : IDLE STATE (DEFAULT) HAS RESUMED"
[ $DEBUG == "true" ] && echo "ACTION: NONE"
[ $DEBUG == "true" ] && echo ""
fi
fi
# KEEP TRACK OF WHAT THE PREVIOUS COMMAND WAS.
# THIS MAY BE USEFUL TO TRACK WHEN MONITORING OTHER CAN BUS IDs.
LASTREMOTE=$REMOTE
done
#!/bin/bash
STARTED=$( date +%s )
# Sets HVAC preferences when vehicle has been remotely started.
echo "$(date) AUTOHEAT: Initializing."
procs="$( ps -eaf | grep autoheat | grep -v grep | grep -v " $$ " | wc -l )"
if [ $procs -gt 0 ]
then
echo "$(date) AUTOHEAT: ERROR - more than one process running! Exiting."
exit 1
fi
# If the blower motor is off, turn on the HVAC system.
FANSPEED=$( /home/pi/bin/fanspeed )
[ "$FANSPEED" == "0" ] && {
echo "$(date) AUTOHEAT: turning on HVAC system"
cansend can0 2D3#0700000000010000
sleep 4.1
}
# Store settings
VENTMODE=$(/home/pi/bin/ventmode)
FANSPEED=$(/home/pi/bin/fanspeed)
echo "$(date) AUTOHEAT: Current VENT: $VENTMODE and SPEED: $FANSPEED"
# Mute the stereo
echo "$(date) AUTOHEAT: Muting the radio"
/home/pi/bin/mute ON ; sleep 0.31
# Turn the fan all the way up
echo "$(date) AUTOHEAT: setting fan to MAX"
/home/pi/bin/fanspeed 7
# Turn on the HVAC front defroster
# This also turns OFF the air conditioner and turns OFF air recirculation.
echo "$(date) AUTOHEAT: clearing modes via the front defroster"
/home/pi/bin/ventmode 00 ; sleep 1.12
# Select a vent combination of windshield and floor
echo "$(date) AUTOHEAT: directing air to windshield and floor"
ventmode 02 ; sleep 1.12
# Turn on air recirculation.
# This automatically causes the A/C to engage, so we'll need to undo that.
echo "$(date) AUTOHEAT: recirculating air"
cansend can0 2D3#0700000000000200
sleep 1.1
# Start setting the driver side to maximum heat setting
# Just 8 steps at first.
for i in `seq 1 8`
do
cansend can0 2D3#0700000000040000
sleep 0.36
done
sleep 0.6
echo "$(date) AUTOHEAT: turning OFF the AC system"
# Turn off the A/C cooling (was turned on with recirculate mode)
cansend can0 2D3#0700000000000100
sleep 0.6
echo "$(date) AUTOHEAT: setting temperature to MAX"
# Finish setting the driver side to maximum heat setting
# Now 18 more steps.
for i in `seq 1 18`
do
cansend can0 2D3#0700000000040000
sleep 0.36
done
sleep 0.6
# Alter the passenger temperature up and down to break any temperature sync
echo "$(date) AUTOHEAT: Syncing driver/passenger settings"
cansend can0 2D3#0700000000100000
sleep 0.36
cansend can0 2D3#0700000000200000
sleep 1.93
# Engage the Driver / Passenger temperature Sync
cansend can0 342#0000000400
sleep 1.61
echo "$(date) AUTOHEAT: exiting normally."
#!/bin/bash
STARTED=$( date +%s )
# Sets HVAC preferences when vehicle has been remotely started.
echo "$(date) AUTOCOOL: Initializing."
procs="$( ps -eaf | grep autoheat | grep -v grep | grep -v " $$ " | wc -l )"
if [ $procs -gt 0 ]
then
echo "$(date) AUTOCOOL: ERROR - more than one process running! Exiting."
exit 1
fi
# ALL PREFLIGHT CHECKS HAVE ALREADY BEEN DONE.
# WE CAN BEGIN OUR WORK IMMEDIATELY.
# If the blower motor is off, turn on the HVAC system.
FANSPEED=$( /home/pi/bin/fanspeed )
[ "$FANSPEED" == "0" ] && {
echo "$(date) AUTOCOOL: turning on HVAC system"
cansend can0 2D3#0700000000010000
sleep 4.1
}
# Store settings
VENTMODE=$(/home/pi/bin/ventmode)
FANSPEED=$(/home/pi/bin/fanspeed)
echo "$(date) AUTOCOOL: Active VENT $VENTMODE and SPEED $FANSPEED"
# Mute the stereo
echo "$(date) AUTOCOOL: Muting the radio"
/home/pi/bin/mute ON ; sleep 0.31
# Set the fan speed to maximum
echo "$(date) AUTOCOOL: setting fan to MAX"
/home/pi/bin/fanspeed 7
# Set the front defroster (which deactivates recirculation mode and AC mode)
echo "$(date) AUTOCOOL: clearing modes with front defroster"
/home/pi/bin/ventmode 00
sleep 1.12
# Now, select the exact blower we want (the main vents)
echo "$(date) AUTOCOOL: directing air to panel vents"
ventmode 08
# Start setting the driver side to maximum cool setting
# Just 8 steps at first.
for i in `seq 1 8`
do
cansend can0 2D3#0700000000080000
sleep 0.36
done
sleep 0.6
# Turn on the A/C cooling (turns on with recirculate mode)
echo "$(date) AUTOCOOL: Turning on AC system"
cansend can0 2D3#0700000000000100
sleep 0.6
echo "$(date) AUTOCOOL: setting temperature to LOW"
# Finish setting the driver side to maximum cool setting
# Now 18 more steps.
for i in `seq 1 18`
do
cansend can0 2D3#0700000000080000
sleep 0.36
done
sleep 0.6
# Turn OFF air recirculation (which came on with the AC)
echo "$(date) AUTOCOOL: Turning OFF air recirculation"
cansend can0 2D3#0700000000000200
echo "$(date) AUTOCOOL: Syncing driver/passenger settings"
# Alter the passenger temperature down and up to break any
# existing temperature sync
cansend can0 2D3#0700000000200000
sleep 0.36
cansend can0 2D3#0700000000100000
sleep 0.63
sleep 1.3
## Sync the driver/passenger HVAC controls
cansend can0 342#0000000400
sleep 0.61
echo "$(date) AUTOCOOL: exiting normally."
Okay, now I'm seeing the connection. More powerful OBD-II tools also provide for Unified Diagnostic Services commands do assist in things such as bleeding the brakes, (electronically) centering the steering wheel, and purging the DPF (diesel) filter.This can also be big news for Diesel owners wanting to be able to manually initiate a regen as it can be as simple as sending a single canbus command, given we can figure out what that is.
#!/bin/bash
# This script turns text into an EVIC dash message
# STRING TIPS: https://linuxhandbook.com/bash-string-length/
# ARRAY TIPS: https://www.shell-tips.com/bash/arrays/
[ "$2" == "" ] && {
echo "USAGE: $(basename $0) [line] [text]"
echo " Displays [text] on the EVIC music information page"
echo " Valid line numbers are: 2 (artist), 3 (title) 1 (input name)"
echo ""
exit 1
}
FUNCTION=$1
shift
declare -a message
string="$@"
length=${#string}
remainder=$(( ( 3 - ( $length % 3 ) ) % 3 ))
POSITION=1
for i in $( seq 1 $length)
do
message[$POSITION]='00'
POSITION=$(( $POSITION + 1 ))
message[$POSITION]=$(printf "%02X" "'${string:$(( i - 1 )):1}'")
POSITION=$(( $POSITION + 1 ))
done
for i in $( seq 1 $remainder )
do
message[$POSITION]=00
POSITION=$(( $POSITION + 1 ))
message[$POSITION]=00
POSITION=$(( $POSITION + 1 ))
length=$(( $length + 1 ))
done
lines=$(( $length / 3 ))
[ "$DEBUG" == "true" ] && echo "FUNCTION: $function"
[ "$DEBUG" == "true" ] && echo "STRING : $string"
[ "$DEBUG" == "true" ] && echo "LENGTH : $length characters ($lines lines)"
[ "$DEBUG" == "true" ] && echo "ENCODED : ${message[*]}"
POSITION=1;INIT=4
for i in $( seq $(( $lines -1 )) -1 0 )
do
LINE=$(printf "%x" $i)
COMMAND="cansend can0 328#${LINE}0.${INIT}${FUNCTION}"
for j in 1 2 3 4 5 6
do
COMMAND="$COMMAND.${message[$POSITION]}"
POSITION=$(( $POSITION + 1 ))
done
$COMMAND ; sleep 0.002
INIT=0
done
cansend can0 328#00.00.00.00.00.00.00.00
sleep 0.005