Circadian Rhythms, F.lux, and DDC/CI (PART III) WORKING ALPHA!!!

SetBright? SleepTight!

YEAAA IT WORKS!!

YEAAA IT WORKS!!

If you’ve been following this blog, you’ve probably already read parts one & two. If you haven’t, read about it after the break!

“The circadian clock. A precision oscillator that regulates our sleep/wake cycles, our body temperature, our blood pressure,  our hormone secretion, our metabolic pathways, and many other bodily processes(mirror). Hell, weakened or disrupted circadian rhythms have even been implicated in bipolar disorder!(mirror) It’s obviously, a very important mechanism. However, ’tis a mechanism that is disrupted most easily by modern life. The biggest offender is undoubtedly the ubiquitous backlit screen. What can we do about it?” – Circadian Rhythms, F.lux, and DDC/CI (part one)

In part one, I discussed the previous attempts made to alleviate the phase-delaying effects of the backlight (i.e. f.lux), and the failures thereof, I quickly reviewed the windows API, and I laid out my ideas for a novel solution therewith.

In part two, I quickly hacked together a concept program that relied on an external application to actually change the brightness of the screen.

Now, I have a working alpha, written in C#, utilizing the WMI .NET framework API.

Implementation

First, I wanted scientific data – published in a journal – to base screen brightness upon. The paper I found was: “REGIONAL DIFFERENCES IN DIURNAL AND SEASONAL CYCLES OF LIGHTING CONDITIONS AND MELATONIN SECRETION“, (mirror). The authors used a MicroDAQ “Silicon Pyranometer(mirror), to measure light intensity in Poland & Japan. I chose to use the data from Japan, Japan has a far more pronounced solar cycle than Poland.  Unfortunately, the authors presented their data as an Excel chart, without the accompanying data table!

To extract the data, I blew up the chart, took a screenshot, opened it in Paint.NET, mapped the light intensities to their locations on the pixel grid, developed an equation to convert Δpixels to Δlux, and mapped every datapoint on the chart.

Segoe Print is awesome!

The heavily annotated image after work in Paint.NET – Click to enlarge!

yesss_evenbetter.PNG_opt

To confirm the data, I created a chart in Excel with the data I extracted from the screenshot.

The code!!! (zip archive)

Overview of the code (high-level):

The main method does three things. It parses the input arguments, it determines therefrom which of GetBrightness(), GetBrightnessLevels() & SetBrightness(byte), to call, and initializes a tray icon – for future use. mapBright(int,int) remains unchanged, but uses the new solar intensity data. GetBrightness(), GetBrightnessLevels() & SetBrightness() call some widely available.NET code to interact with the Windows management instrumentation. All Console.Write(“stuff”) functions are for debugging, and print various status messages to the command line.

A closer look at the code:

For simplicity, I averaged the pre-peak & post peak light intensity values, and call SetBrightness(hourbright[]) from the ugly switch/case construct in mapBright(int, int). I really should also review the .NET code itself, but that would be very time consuming – time that I don’t have.

Raw code

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;
using System.Text.RegularExpressions;

//EL GPL LICENCE, MOFOs
namespace DisplayBrightnessConsole
    {
   public class BaseConst//#TODO , make this an OPTION that's dynamically configurable at runtime
       {

        public static byte[] hourbright = { 22, 44, 54, 76, 83, 92, 97, 100 };
        public const double version = 0.1;
        }

    class Program
        {
        //static byte[] hourbright = { 22, 44, 54, 76, 83, 92, 97, 100 };

        static void Main(string[] args)
            {
            //IntPtr hdc_;
            //IntPtr iprc_;
            //MONITORENUMPROC ipfnenum_;
            //int dwdata_;
           // bool hello = NativeMethods.EnumDisplayMonitors(null, null,);
            Console.WriteLine("version " + BaseConst.version);
            Console.WriteLine();
            NotifyIcon tray = new NotifyIcon();
            tray.Icon =  SystemIcons.Application;
            //tray.ShowBalloonTip(10000,"fuck yeah!","it works. bitch.", ToolTipIcon.Info);
            //System.Threading.Thread.Sleep(1000);
            //note to self see; system.drawing.drawig2d
            tray.Visible = true;
            //Console.WriteLine("");
            #region noargs
            if (args.Length == 0)
                {
                tray.ShowBalloonTip(1000, "SetBright? SleepTight!", "version " + BaseConst.version + " works, yo", ToolTipIcon.Info);
                Console.WriteLine("DEBUG: Current brightness: " + GetBrightness());
                //System.Threading.Thread.Sleep(5000);
                int hour = DateTime.Now.Hour;
                int min = DateTime.Now.Minute;
                //int hour = 12;
                //int min = 30;
                mapBright( hour, min);
                }
            #endregion
            #region getlevels
            else if (args[0] == "-getlevels")
                {
                byte[] BrightnessLevels = GetBrightnessLevels();
                Console.Write("This monitor supports " + (BrightnessLevels.Length) + " brightness levels: ");
                foreach (byte b in BrightnessLevels)
                    {
                    Console.Write(b.ToString() + ";");
                    }
                //Console.WriteLine("");
                }
            #endregion
            else if (args[0] == "-getwmiinfo") 
                {
                getwmiInfo();
                }
            #region loop
            else if (args[0] == "-loop")//test sequence
                {
                Console.WriteLine("");
                byte[] BrightnessLevels = GetBrightnessLevels();
                byte initbright = GetBrightness();
                Console.WriteLine("");
                Console.WriteLine("");
                foreach (byte b in BrightnessLevels)
                    {
                    SetBrightness(b);
                    //System.Threading.Thread.Sleep(250);
                    Console.WriteLine("Brightness->" + b.ToString());
                    }
                Console.WriteLine("");
                for (int i = 0; i < 17; i++)
                    {
                    for (int m = 0; m < 60; m += 30)
                        {
                        Console.WriteLine(" mapB(" + i + ", " + m + ");");
                        mapBright(i, m);
                        }
                    }
                SetBrightness(initbright);
                tray.Dispose();

                }
            #endregion
            #region lh
            /*
            else if (args[0] == "-lh")
            {
                byte l = System.Convert.ToByte(args[1]);
                byte h = System.Convert.ToByte(args[2]);
                for (int i = l; i < h + 1; i++)
                {
                    SetBrightness(System.Convert.ToByte(i));
                    Console.WriteLine("Current Brightness: " + GetBrightness());
                }
            }*/
            #endregion
            #region interpol
            /*else if (args[0] == "-interpol")
            {
                byte[] BrightnessLevels = GetBrightnessLevels();
                for (int q = 0; q+1 < BrightnessLevels.Length; q++)
                {
                    Console.WriteLine(BrightnessLevels[q] + " - " + BrightnessLevels[q+1]);
                    for (int i = 0; i < 2; i++)                     {                         SetBrightness(BrightnessLevels[q]);                         SetBrightness(BrightnessLevels[q + 1]);                     }                 }             }*/             #endregion             #region TODO             /*             else if (args[0] == "-t")//interpol to target value             {                 oops("Interpol to target value");             }                  */             #endregion             #region time             else if (args[0] == "-time")                 {                 int hour = DateTime.Now.Hour;                 int min = DateTime.Now.Minute;                 Console.WriteLine("Current time is: " + hour + ":" + min);                 }             #endregion             #region else             else//assumes number was input as an input, i.e. "brightness.exe 100"                 {                 int targetBrightness;                 bool res = int.TryParse(args[0], out targetBrightness);                 //parse switch value                 if (res == false)                     {                     Console.WriteLine("Invalid input!, please try again");                     }                 if (res == true)                     {                     if (targetBrightness > 100 || targetBrightness < 0) //handles the wtf case where brightness is more than 100 or less than zero                         {                         Console.WriteLine("What the hell?? Target brightness \"" + targetBrightness + "\" out of bounds!");                         int i = (targetBrightness > 100 ? 100 : 0);
                        byte l = ((byte)i);//required explicit type conversion
                        SetBrightness(l);
                        Console.WriteLine("Brightness set to: \"" + l + "\" instead!");
                        return;
                        }
                    byte h = ((byte)targetBrightness);//required explicit type conversion
                    SetBrightness(h);
                    Console.WriteLine("Current Brightness: " + GetBrightness());
                    }
                }
            #endregion
            }

        private static int ipfenum_(IntPtr param0, IntPtr param1, ref tagRECT param2, IntPtr param3)
            {
            throw new NotImplementedException();
            }
        static void oops(String feature)
            {
            Console.WriteLine("....oops");
            Console.WriteLine("Feature \"" + feature + "\" not implemented yet. How embarassing!");
            }
        static byte GetBrightness()
            {
            Console.WriteLine("DEBUG: CALLING GETBRIGHTNESS - System.Management.ManagementScope ");
            System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");//define scope (namespace)
            Console.WriteLine("DEBUG: System.Management.ManagementScope s = " + s);

            System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightness");//define query
            Console.WriteLine("DEBUG: System.Management.SelectQuery q = " + q);

            System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
            Console.WriteLine("DEBUG: System.Management.ManagementObjectSearcher mos = " + mos); 

            System.Management.ManagementObjectCollection moc = mos.Get();//output current brightness
            Console.WriteLine("DEBUG: System.Management.ManagementObjectCollection moc = " + moc);

            byte curBrightness = 0;//store result
            foreach (System.Management.ManagementObject o in moc)
                {
                curBrightness = (byte)o.GetPropertyValue("CurrentBrightness");
                break; //only work on the first object
                }
            moc.Dispose();
            mos.Dispose();
            return curBrightness;
            }
        static byte[] GetBrightnessLevels()
            {
            Console.WriteLine("DEBUG: CALLING GETBRIGHTNESSLEVLELS System.Management.ManagementScope ");

            System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");//define scope (namespace)
            System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightness");//define query
            Console.WriteLine("DEBUG: System.Management.SelectQuery q = " + q);

            System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
            Console.WriteLine("DEBUG: System.Management.ManagementObjectSearcher mos = " + mos); 
            System.Management.ManagementObjectCollection moc = mos.Get();//output current brightness
            Console.WriteLine("DEBUG: System.Management.ManagementObjectCollection moc = " + moc);
            byte[] BrightnessLevels = new byte[0];//store result
            Console.Write("DEBUG:  targetBrightness -> ManagmentObject:");
            foreach (System.Management.ManagementObject o in moc)
                {
                Console.Write(" " + o + "; ");
                BrightnessLevels = (byte[])o.GetPropertyValue("Level");
                break; //only work on the first object
                }
            moc.Dispose();
            mos.Dispose();
            return BrightnessLevels;
            }
        static void getwmiInfo()
            {

            Console.WriteLine("DEBUG: CALLING GETBRIGHTNESSLEVLELS System.Management.ManagementScope ");

            System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");//define scope (namespace)
            System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightness");//define query
            Console.WriteLine("DEBUG: System.Management.SelectQuery q = " + q);

            System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
            Console.WriteLine("DEBUG: System.Management.ManagementObjectSearcher mos = " + mos);
            System.Management.ManagementObjectCollection moc = mos.Get();//output current brightness
            Console.WriteLine("DEBUG: System.Management.ManagementObjectCollection moc = " + moc);
            Console.WriteLine("DEBUG: System.Management.ManagementObjectCollection mos.Get = " + mos.Get());
            Console.WriteLine("DEBUG: System.Management.ManagementObjectCollection mos.Options = " + mos.Options);
            byte[] BrightnessLevels = new byte[0];//store result
            Console.Write("DEBUG:  targetBrightness -> ManagmentObject:");
            foreach (System.Management.ManagementObject o in moc)
                {
                Console.WriteLine(o.ClassPath);
                Console.WriteLine(o.Container);
                Console.WriteLine(o.Options);
                Console.WriteLine(o.Path);
                Console.WriteLine(o.Properties);
                Console.WriteLine(o.Qualifiers);
                Console.WriteLine(o.Scope);
                Console.WriteLine(o.Site);
                Console.WriteLine(o.SystemProperties);

                List newget = new List();
                newget.Add(o.GetText(System.Management.TextFormat.Mof));
                newget.Add(o.GetText(System.Management.TextFormat.CimDtd20));
                newget.Add(o.GetText(System.Management.TextFormat.WmiDtd20));
                //string[] newget = o.GetText(System.Management.TextFormat.Mof);
                //string. = o.GetText(System.Management.TextFormat.Mof);

                //string newget1 = o.GetText(System.Management.TextFormat.Mof);      string[] newgetwords = Regex.Split(newget1, ">");
                //string newget2 = o.GetText(System.Management.TextFormat.CimDtd20); string[] newgetwords2 = Regex.Split(newget2, ">");

                string newget3 = o.GetText(System.Management.TextFormat.WmiDtd20); string[] newgetwords3 = Regex.Split(newget3, ">");
                string[][] lesstrings = new string[1][] { /*newgetwords, newgetwords2, */newgetwords3 };

                Console.WriteLine();
                Console.WriteLine();

                for (int b = 0; b < lesstrings.Length; b++)                     {                     foreach (string n in lesstrings[b])                         {                         //Console.WriteLine();                         Console.WriteLine(">");
                        Console.Write(n);
                        //Console.WriteLine();
                        }
                    }
                Console.WriteLine(o.GetPropertyQualifierValue("Active", "CIMTYPE"));
                Console.WriteLine(o.GetPropertyQualifierValue("InstanceName", "CIMTYPE"));
                Console.WriteLine(o.GetPropertyValue("__RELPATH"));
                Console.WriteLine(o.GetPropertyValue("__PATH"));
                /*   
                 System.Management.ManagementClass mclass = new System.Management.ManagementClass("WmiMonitorBrightnessMethods");
                 mclass.Scope = new System.Management.ManagementScope(@"\\.\root\wmi");
                 System.Management.ManagementObjectCollection instances = mclass.GetInstances();

                 // I assume you get one instance per monitor
                 foreach(System.Management.ManagementObject instance in instances)
                 {
                 ulong timeout = 1; // in seconds
                 ushort brightness = 50; // in percent
                 object[] args = new object[] { timeout, brightness };
                 instance.InvokeMethod("WmiSetBrightness", args);
                 }
             mclass.Dispose();
             instances.Dispose();
       */

                }
            moc.Dispose();
            mos.Dispose();
            }

        static void SetBrightness(byte targetBrightness)
            {
            Console.WriteLine("Setting Brightness: " + targetBrightness);
            NotifyIcon tray = new NotifyIcon();
            tray.Icon = SystemIcons.Application;
            tray.Visible = true;
            tray.ShowBalloonTip(1000, "Setting Brightness: ", (targetBrightness.ToString()), ToolTipIcon.Info);
            System.Management.ManagementScope s = new System.Management.ManagementScope("root\\WMI");//define scope (namespace)
            Console.WriteLine("DEBUG: System.Management.ManagementScope s = " + s);
            System.Management.SelectQuery q = new System.Management.SelectQuery("WmiMonitorBrightnessMethods");//define query
            Console.WriteLine("DEBUG: System.Management.SelectQuery q = " + q);
            System.Management.ManagementObjectSearcher mos = new System.Management.ManagementObjectSearcher(s, q);
            Console.WriteLine("DEBUG: System.Management.ManagementObjectSearcher mos = " + mos);
            System.Management.ManagementObjectCollection moc = mos.Get();
            Console.WriteLine("DEBUG: System.Management.ManagementObjectCollection moc = " + moc);

            foreach (System.Management.ManagementObject o in moc)//output current brightness
                {
                o.InvokeMethod("WmiSetBrightness", new Object[] { UInt32.MaxValue, targetBrightness }); //note the reversed order - won't work otherwise!
                break; //only work on the first object
                }            //Console.WriteLine("   ");
            Console.WriteLine("DEBUG: moc + mos: disposing");
            moc.Dispose();
            mos.Dispose();
            }
        static void mapBright(int y, int x)
            {
            if (y < 8 || y > 15)
                {
                Console.Write("night time! Bright -> 0! ");
                SetBrightness(0);
                }
            switch (y)
                {
                case 8:
                    SetBrightness(BaseConst.hourbright[((x < 30) ? 0 : 1)]);//if not yet 8:30, 22; else 44
                    //Console.Write("hbri[" + (((x < 30) ? 0 : 1)) + "]");
                    break;
                case 9:
                    SetBrightness(BaseConst.hourbright[1 + ((x < 30) ? 0 : 1)]);
                    //Console.Write("hbri[" + (1 + ((x < 30) ? 0 : 1)) + "]");
                    break;
                case 10:
                    SetBrightness(BaseConst.hourbright[2 + ((x < 30) ? 0 : 1)]);
                    //Console.Write("hbri[" + (2 + ((x < 30) ? 0 : 1)) + "]");
                    break;
                case 11:
                    SetBrightness(BaseConst.hourbright[3 + ((x < 30) ? 0 : 1)]);
                    //Console.Write("hbri[" + (3 + ((x < 30) ? 0 : 1)) + "]");
                    break;
                case 12:
                    SetBrightness(BaseConst.hourbright[7 + ((x < 30) ? 0 : -1)]);
                    //Console.Write("hbri[" + (7 + ((x < 30) ? 0 : -1)) + "]");
                    break;
                case 13:
                    SetBrightness(BaseConst.hourbright[7 + ((x < 30) ? 0 : -1)]);
                    //Console.Write("hbri[" + (7 + ((x < 30) ? 0 : -1)) + "]");
                    break;
                case 14:
                    SetBrightness(BaseConst.hourbright[6 + ((x < 30) ? 0 : -1)]);
                    //Console.Write("hbri[" + (6 + ((x < 30) ? 0 : -1)) + "]");
                    break;
                case 15:
                    SetBrightness(BaseConst.hourbright[5 + ((x < 30) ? 0 : -1)]);
                    //Console.Write("hbri[" + (5 + ((x < 30) ? 0 : -1)) + "]");
                    break;
                }
            }
        }
    }

If you want the compiled binary, download it below. Background application functionality is not implemented as of yet – if you desperately need the benefits of this application, then run it hourly as a scheduled task.

SETBRIGHT_SLEEPTIGHT_RELEASE_0.1

One last note

This will not work on every computer! It’s far more likely to work if your computer is either new, or a laptop. It seems that WMI doesn’t support older/desktop monitors for some reason. I’ll need to get the low level DDC/CI working for that.

~ by Alexander Riccio on May 4, 2013.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
Shelly L. Miller

I am an environmental engineer. I teach and research urban air pollution.

Lucky's Notes

Notes on math, coding, and other stuff

AbandonedNYC

Abandoned places and history in the five boroughs

Open Mind

KIDS' LIVES MATTER so let's stop climate change

I learned it. I share it.

A software engineering blog by György Balássy

Kitware Inc

Delivering Innovation

The Electric Chronicles: Power in Flux

If someone ever tells you that you don't need more power, walk away. You don't need that kind of negativity in your life.

Ted's Energy Tips

Practical tips for making your home more comfortable, efficient and safe

love n grace

feel happy, be happy

Recognition, Evaluation, Control

News and views from Diamond Environmental Ltd.

greg tinkers

Sharing the successes and disasters.

Sam Thursfield

Software and technology from Galicia, Spain

Cranraspberry Blog

Sharing the things I love

Biosingularity

Advances in biological systems.

The Embedded Code

Designing From Scratch

Sean Heelan's Blog

Software Exploitation and Optimisation

EduResearcher

Connecting Research, Policy, and Practice in Education

Popehat

A Group Complaint about Law, Liberty, and Leisure

warnersstellian.wordpress.com/

Home & Kitchen Appliance Blog

Bad Science Debunked

Debunking dangerous junk science found on the Internet. Non-scientist friendly!

4 gravitons

The trials and tribulations of four gravitons and a physicist

Strange Quark In London

A blog about physics, citylive and much procastination

The Lumber Room

"Consign them to dust and damp by way of preserving them"

In the Dark

A blog about the Universe, and all that surrounds it

andrea elizabeth

passionate - vibrant - ambitious

Probably Dance

I can program and like games

a totally unnecessary blog

paolo severini's waste of bandwidth

Musing Mortoray

Programming and Life

PJ Naughter's space

Musings on Native mode development on Windows using C++

  Bartosz Milewski's Programming Cafe

Category Theory, Haskell, Concurrency, C++

Brandon's Thoughts

Thoughts on programming

David Crocker's Verification Blog

Formal verification of C/C++ code for critical systems

10 Minute Astronomy

Stargazing for people who think they don't have time for stargazing.

One Dev Job

notes of an interactive developer

Chief Cloud Architect & DevSecOps SME, Enterprise Architect, Agile Coach, Digital Transformation Leader, Presales & Tech Evangelist, Development Manager, Agilist, Mentor, Speaker and Author

TOGAF Certified Enterprise Architect • AWS Cloud Certified Solutions Architect • Azure Cloud Certified Solutions Architect • Scrum Alliance: Certified Scrum Professional (CSP), Certified Agile Leadership I (CAL 1), CSM, ACSM • Kanban Management Professional (KMP I & KMP II), Certified Enterprise Agility Coach (CEAC) • SAFe: Certified SAFe Architect, SAFe DevOps, Release Train Engineer (RTE), SAFe Consultant (SPC) • Certified Less Practitioner (CLP), Six Sigma (Greenbelt), Training from the Back of the Room (TBR) Trainer • Certified Agile Coach & Facilitator: ICP-ACF & ICP-ACC

The Angry Technician

No, the Internet is not broken.

Kenny Kerr

Creator of C++/WinRT and the Windows crate for Rust • Engineer on the Windows team at Microsoft • Romans 1:16

IT affinity!

The Ultimate Question of Life, the Universe, and Everything is answered somewhere else. This is just about IT.

Eat/Play/Hate

The ramblings of a crazed mind

Molecular Musings

Development blog of the Molecule Engine

%d bloggers like this: