Switching silent profile during sleep

I think you wouldn't be pleased if some unimportant call or, what is much worse, SPAM SMS message wakes you up. Solution would be to switch silent profile when you sleep. You can do it by hand ever day, but why not to automate it? You can use silencer, but it has very simple logic, which silences phone when it is late, but not when you sleep. What about something more intelligent? This is second article about ET-Prolog. First article was not rated high, i suspect because nobody understood how to work with it. So here is a practical example. You would need ET-Prolog to run programs, described here. New version of ET-Prolog already includes code, described here.

Simple silencer approach

Ensure, that your et-prolog/init.pl contains
consult('/opt/maemo/usr/lib/et-prolog/n900utils.pl'),
initPhoneProfile,
It is general initialization needed for most cases. Add following code to et-prolog/init.pl:
addGuard(newAlarmTerm('time to sleep', false, '(*.*.* 23:00)-(*.*.* 10:00)'), [[changedGuard]], 'et-prolog/simple_silent_sleep.pl'),
It says, that we need new temporal term called "time to sleep" which becomes true at 23:00 and becomes false at 10:00. When it changes value et-prolog/simple_silent_sleep.pl should be executed. Save init.pl and start editing et-prolog/simple_silent_sleep.pl
(
        alarmTerm('true', 'time to sleep'),
        (previous(alarmTerm('false', 'time to sleep'));\+(previous(_))),
        string_to_atom(PROFILESTR, 'silent'), phoneProfile(PROFILESTR)
);(
        alarmTerm('false', 'time to sleep'),
        (previous(alarmTerm('true', 'time to sleep'));\+(previous(_))),
        string_to_atom(PROFILESTR, 'general'), phoneProfile(PROFILESTR)
);true.
This means: if it is time to sleep now, but was not a moment ago or it is time to sleep and we don't know what was a moment ago, switch to silent profile. if it is not time to sleep now, but was a moment ago or it is not time to sleep and we don't know what was a moment ago, switch to general profile.
That's all. It took only 15 lines of code.

Making things complicated

I don't always go to bed at 23:00 and stand up at 10. But I usually set alarm, when I get up early and I switch light when I go to bed. So I want my phone switch to general profile when alarm rings, or at 10:00 if I haven't set an alarm. And I want it to go to silent mode not at 23:00 but after 23:00 when it becomes dark (remember, that we have ambient light sensor). This program would be much more complicated, about two screens of code, but still much less than it would take on usual programming language.
Ensure, that your et-prolog/init.pl contains
consult('/opt/maemo/usr/lib/et-prolog/n900utils.pl'),
initPhoneProfile,
Add following code to et-prolog/init.pl:
% Switching silent profile at night
newTemporalTerm('notification events', false),
newTemporalTerm('slept', false),
addGuard(newTemporalTerm('wait for dark', 'false'), [[changedGuard]], 'et-prolog/wait_for_dark.pl'),
addGuard(newTemporalTerm('sleeping', 'false'), [[changedGuard]], 'et-prolog/sleep_profile.pl'),
addGuard(newTemporalTerm('alarm ringing', false), [[nEqualGuard(false)]], 'et-prolog/silent_sleep.pl'),
addGuard(newAlarmTerm('time to sleep', false, '(*.*.* 23:00)-(*.*.* 10:00)'), [[changedGuard]], 'et-prolog/silent_sleep.pl'),
addDBusListener('method_call', '/org/freedesktop/Notifications', 'org.freedesktop.Notifications', 'Notify', true, false, temporalTerm(_, 'notification events')),
addGuard(temporalTerm(_, 'notification events'), [[nEqualGuard(false)]], 'et-prolog/notification_eval.pl'),
consult('et-prolog/silent_sleep.pl'),
Here we define several temporal terms and set up actions, that should be taken when these terms change value or are equal/less than specific value. We also register DBus listener which is needed for catching alarms. Let's start with helper scripts.

Catchng alarm

et-prolog/notification_eval.pl should contain
?- write('Notification recieved'),
(
        temporalTerm(['notify-clock-alarm' | _], 'notification events'),
        addHint('alarm ringing', true),
        addHint('alarm ringing', false),
        write('Alarm ringing')
); true.
If the first argument of received event is 'notify-clock-alarm', change 'alarm ringing' value to true and then to false. Alarm ringing would be true only during one epoch. This is how events are modeled in ET-Prolog.

Waiting for dark

et-prolog/wait_for_dark.pl should contain
?-
(
        temporalTerm('true', 'wait for dark'),
        (previous(temporalTerm('false', 'wait for dark'));\+(previous(_))),
        addTimerHint(lightSensor(_, 0, 1), 60),
        addGuard(lightSensor(_, 0, 1), [[lessGuard(50)]], 'et-prolog/silent_sleep.pl'),
        addGuard(lightSensor(_, 0, 1), [[alwaysGuard]], '')
);(
        temporalTerm('false', 'wait for dark'),
        (previous(temporalTerm('true', 'wait for dark'));\+(previous(_))),
        delTimerHint(lightSensor(_, 0, 1), 60),
        delGuard(lightSensor(_, 0, 1), [[lessGuard(50)]], 'et-prolog/silent_sleep.pl'),
        delGuard(lightSensor(_, 0, 1), [[alwaysGuard]], '')
);true.
You have already seen similar code in simple example. If 'wait for dark' has changed from false to true then start polling light sensor once a minute and call et-prolog/silent_sleep.pl if it is less, than 50. Additional guard with empty script name is needed because ET-Prolog may forget temporal terms values if there are no scripts interested in them.
If 'wait for dark' has changed from true to false, then we don't need to watch for light sensor.

Switching profiles

et-prolog/sleep_profile.pl should contain
?-
(
        temporalTerm('true', 'sleeping'),
        previous(temporalTerm('false', 'sleeping')),
        string_to_atom(PROFILESTR, 'silent'), phoneProfile(PROFILESTR)
);(
        temporalTerm('false', 'sleeping'),
        previous(temporalTerm('true', 'sleeping')),
        string_to_atom(PROFILESTR, 'general'), phoneProfile(PROFILESTR)
);(
        % Only possible if there is no previous epoch
        true
).
The same scheme. If user sleeps now but didn't sleep before, switch to silent profile. And switch to general profile when user stops sleeping. Notice, that if user changes profile manually when phone thinks, that he is sleeping, profile would remain general. So you can make phone understand, that this night it should wake you up.

Main logic

et-prolog/silent_sleep.pl should contain
?-                                                        
((
        % Alarm rang, not sleeping any more
        temporalTerm('true', 'alarm ringing'),
        addHint('sleeping', false),
        addHint('wait for dark',false)
); true),
Alarm means, that user is not sleeping. addHint('wait for dark',false) was added in a case if alarm rang when ET-Prolog was only waiting untill it becomes dark. If we won't do it, light sensor would still be polled and it would drain your battery.
(
        % Time to sleep, user is not sleeping, and had not slept this night
        temporalTerm('false', 'sleeping'),
        temporalTerm('false', 'slept'),
        alarmTerm('true', 'time to sleep'),
        write('Time to sleep'),
If one of these terms has other value this subgoal would not succeed and ET-Prolog would process next alternative.
        ((
                % Last 5 minutes it was dark
                always(((ago(SECONDS), SECONDS > 300); (lightSensor(LIGHT, 0, 1), LIGHT < 50))),
                sometimes((ago(SECONDS), SECONDS > 300)),
When program starts there is no information about previous epochs, so always(...) would succeed. That's why we ensure, that we have epoch older than 300 seconds.
                write('User sleeps'),
                addHint('sleeping', true),
                addHint('slept', true),
                addHint('wait for dark',false)
We just add hints. If it would lead to temporal term values changes, than guards would work and needed scripts would be run automatically. We have 'slept' term which is true, when user has already slept at this day, so we should not expect him to sleep again even if it is still early morning.
        );(
                % It is light here, check light sensor every minute
                write('Waiting until it becomes dark'),
                addHint('wait for dark',true)
        ))
);(
        % Sleeping time is over, time to get up
        alarmTerm('false', 'time to sleep'),
        previous(alarmTerm('true', 'time to sleep')),
        write('It is morning'),
        addHint('slept', false),
        addHint('sleeping', false),
        addHint('wait for dark',false)
);
Following true is just to make this goal succeed if we don't need to perform any actions.
true.

Future improvements

When I go to bed it is usually silent around. So phone could use it microphone to check, that I'm sleeping. But I didn't have time to implement ambient noise level term in ET-Prolog.
It is not pleasant to find out, that phone has discharged at night and you don't have a time to charge it. If phone's battery is low and I went to bed I can ask me to charge it, before i fall asleep.
If there was answering machine application for n900 it would be possible to warn caller that user is sleeping, give him a time to decline call and if he didn't threat call as urgent and ring.

Comments

Problem with activation

Hi there, I dont know if I am writing in a proper board but I have got a problem with activation, link i receive in email is not working... [URL WAS HERE]

Try using "I've forgot my

Try using "I've forgot my password" feature (right under login form). If it doesn't work, tell me your nickname, so I would be able to activate it by hand.
I'll look at activation procedure too.

Check accelerators

Why not check for DARK, TIME and NO-MOTION.

When you are out, and carry your phone in your pocket, its probably dark, and it might be past 11pm so your phone will turn silent. BUT if you check the accelerators and the phone is moving, it should prevent the phone from switching to silent.

Normally when you go to bead, you'll place your phone somewhere, so:
Check time -> If time >= 23 && time <= 8 then check DARK, if DARK is true, check for NoMotion, if no NoMotion for 30min, turn phone silent.

Cheers
Bjoern

Additional idea (accelerometer)

Just as additional idea:
If your phone is in the pocket, the phone would see its dark. So if you additionally check that there is no moving when its dark by getting the accelerometers this case would be handled.

Gunni

Accelerometer support

Thank you. That`s the case accelerometer can be used for. It is not supported now and previously we were in doubt if it`s worth implementing. There is one more thing which can be used: the proximity sensor. If it is covered there is high possibility that the phone is in pocket, bag or lies on the table upside down. In this case ambient light sensor can be ignored.

just having a quick read of

just having a quick read of this from my n900! fantastic ideas here! i could have done with something like this, this morning when my i got a load of server down messages at 8am.

thanks a lot, ill be trying this out tonight.

andy (teh @ maemo)

Smart!

I agree, your very much putting the 'smart' into smart phone. This is something I've thought about but had no idea how to implement. For example I'd like to have a mode where the phone switches to 'vibrate' every time I put it in my pocket. Given something like this I could have it check for darkness, and maybe ambient noise. And the sleep idea is great too. When its dark, and there's no noise assume sleep. Very cool indeed.

You have proximity sensor on

You have proximity sensor on the phone, which would be definitely covered, when it is in the pocket. As said several posts upper, accelerometer can be used too (when it would be supported by ET-Prolog). But be careful with battery usage: these sensors need energy to work, especially accelerometer. So you have to think about polling intervals and using of minimal amount of sensors so as not end with discharged phone.

Why the painful license agreement?

Asking for an email address before download, a form filling and adding restrictions to the license? If you are lacking feedback on ETProlog as seems to be the case, don't be surprised. I was interested until I saw these restrictions.

You really think, that this

You really think, that this license is painful? Have you ever read other licenses? I want to know how much people have downloaded the package. That's why I ask for email. I don't check it for being valid. Feel free to enter any string as email, if you enter the same string every time you download package. If extras-devel would provide such statistics I would use it. Copying limitations have the same source. And I highly dislike when people distribute my software from their blogs instead of linking to official site. I wouldn't say a word if they track updates and add new versions in their posts. But they don't and users get OLD versions. Feedback form? It does not contain private information and, actually, of course I'm not going to hunt those, who didn't fill it in. But I would appreciate if you would fill it in. Do you have any arguments other than "author wants me to put two checkboxes and give little amount of non confidential information?"

smart phone

If there was answering machine application for n900 it would be possible to warn caller that user is sleeping, give him a time to decline call and if he didn't threat call as urgent and ring.

Now that's what I'd call a smart phone. I'd also like to see location awareness for switching profiles. At $gym I want silent profile, or at $lunch-place, for instance. ;-)

Way to go!

Location awareness and profile switching

Location support is already implemented through liblocation integration. Profile switching is also supported. So your use case can already be expressed in ET-Prolog.
In example init.pl (coming with with ET-Prolog) there is "switching silent profiles during lections in university". It has not been tested thoroughly yet but should work. You can adopt this example for your needs.
You should also select correct location method. GNSS method which uses GPS receiver drains battery so you should stick to ACWP method which is cellular base station based. It is much less precise but doesn't lead to battery drain and works inside buildings.