(Signal to) Noise meter + Mail

emaildayoff_snippet(ITP 4-in-4 day 4+1, or how i learned to stop worrying and love blowing deadlines)

to complete the signal to noise meter previously posted i wrote up an apple script which calculates a ratio of messages in my mail inbox to the junk messages which have been caught. the apple script then sends that ratio via serial to the signal to noise meter. i’ve set up a rule in mail.app to trigger the script every time a message comes in. the serial output (ascii only, it seems) is thanks to SerialPort X.

it’s certainly not perfect…having a lot of read messages stagnating in the inbox brings the ratio down…but i’m posting the code below so maybe someone can figure a better way.

also, the script wasn’t triggering when called directly from mail’s rules…my workaround was to have a launcher script run ‘do shell script “osascript ” signalToNoise.scpt’. for some reason this worked when the launcher script was triggered by mail – YMMV.

oh! it just when off as i was writing this entry…the light came on, and the needle swung high….i need to clean out the junk mail!

code after the break (i always wanted to write “after the break”)

Apple Script Code

Make a new script and copy it to your ~/Library/Scripts folder.

tell application "Mail"
	set junkCount to unread count of junk mailbox as number
	set inboxCount to unread count of inbox as number

	(* this returns a count of all the messages in the inbox *)
	set inboxMsgs to count messages of inbox

	(* this returns only the unread count of the inbox *)
	set total to 0
	repeat with mb in mailboxes
		set total to total + (unread count of mb) as number
	end repeat

	(* this will count all the messages *)
	set mailboxMsgs to 0
	repeat with mb in mailboxes
		set mailboxMsgs to mailboxMsgs + (count messages of mb)
	end repeat

	if inboxMsgs > 0 then
		set sn to junkCount / (inboxMsgs + junkCount) as number
		set sn to 0
	end if

	(* establish the baseline value for the meter *)
	if sn < 0.3 then
		set sn to 0.3
	end if

	display dialog ("Signal to Noise - " & sn)

end tell

set portName to (item 1 of (serialport list))
set portRef to serialport open portName bps rate 9600
if portRef is equal to -1 then

	display dialog "Could not open Serial Port: " & portName

	delay 2
	set sendVal to 10 * sn as integer
	serialport write sendVal to portRef (* sn should be a ratio *)
	delay 3

	serialport close portRef
end if

(* this will list all the serial ports available *)
serialport list

<h3>Arduino code</h3>
This is for the meter, specifically, but could be easily updated for other output devices.

  Signal / noise meter
  2009 Robert Carlsen // robertcarlsen.net

  driving a mechanical decibel meter with PWM via Arduino

  raw analogWrite values:
  3 : -4 (bottom of scale)
  9 : +6 (top of scale)

  draws about 1mA at top of scale

  running through an LED and 220ohm resistor to provide more load
  and to protect the Arduino from (possible) reverse current as the
  springs pull the needle past the electromagnet when it's turned off

int meterPin = 3;
byte val;

int maxVal = 40; // this is adjusted for the load of the meter, resistor and led

int inputMode = 0;
int numModes = 3;

void setup() {
  pinMode(meterPin, OUTPUT);

void loop(){

    val = Serial.read();

    // change modes
    if(val == 255){
      inputMode = (inputMode + 1) % numModes;
      val = 0;

    // allow mode switching. default is to accept ascii 0-9
    // second mode is to accept raw bytes 0-254
    // third mode echos the received values for testing
    case 0: // direct input from Serial Monitor
      // converting ascii values to int for math
      val = constrain(val,48,57) - 48;
      // mapping to a useable range
      val = map(val,0,9,0,maxVal);
    case 1: // input bytes
      // reserve 255 for changing mode
      val = map(val,0,254,0,maxVal);
    case 2: // monitor input values
      Serial.print(val , DEC);

  // send value:
  if(inputMode != 2)
  analogWrite(meterPin, (int)val); 







Leave a Reply