openwebnet / openwebnet-android

OpenWebNet Android client for My Home BTicino and Legrand home automation system
https://openwebnet.xyz
MIT License
34 stars 21 forks source link

Enhancement: Add the "Automation" feature #5

Closed moreau-nicolas closed 8 years ago

moreau-nicolas commented 8 years ago

Hello,

The "Custom Device" feature allows you to control automation devices (eg. shutters) but you have to create a separate device for opening, closing and stopping the shutter, which is not very convenient.

I propose adding an AutomationActivity, similar to the LightingActivity.

A new card type will be used to manage automation devices. It will have two buttons, one for each moving direction. The button appearance will change to reflect state (stopped, moving up, moving down).

moreau-nicolas commented 8 years ago

I have started implementing this, it is mostly finished.

niqdev commented 8 years ago

Well done! I would like to point out just few hints:

moreau-nicolas commented 8 years ago

Thanks for the tips !

Here is what I had in mind for the card design: automation-card

If an error occurs, both arrows are invisible and the usual alert icon is visible.

I'll take a look at migration strategies. I'll get back to you regarding the FloatingActionsMenu, it requires some thought. :)

niqdev commented 8 years ago

I like the Automation card! In the mean while, just for you to know, I'm working on this library for IpCam, when it will be ready I'll integrate it on this project as dependency.

moreau-nicolas commented 8 years ago

Quick question regarding the unit tests : how do you run them ? I keep having a Dagger compilation error : com.github.openwebnet.component.DaggerApplicationComponentTest is not found.

I can't see the class in app/build/generated/source/apt. Have you had this problem before ?

niqdev commented 8 years ago

Sorry but I'm on holiday for a couple of days so I can't verify without pc. Anyway I remember that I had to configure Roboelectric and JUnit test runner $MODULE_DIR$ to run the tests on mac.

moreau-nicolas commented 8 years ago

Thanks for the answer, have a nice holiday !

niqdev commented 8 years ago

Hi, well done!

Could you please tell me more about MockitoConfiguration#enableClassCache?

I had some trouble to mock/spy correctly OpenWebNet client in LightServiceTest#lightService_turnOn, do you have any idea?

Currently I have the following error running the application with a previous version already installed. You can reproduce the error installing before a previous version git checkout v1.3.0, same for other tags, can you verify please?

03-01 07:14:01.069 4368-4368/com.github.openwebnet E/OpenWebNet: environment-FIND_ALL
                                                                 io.realm.exceptions.RealmMigrationNeededException: Field 'uuid' does support null values in the existing Realm file. Remove @Required or @PrimaryKey from field 'uuid' or migrate using io.realm.internal.Table.convertColumnToNotNullable().
                                                                     at io.realm.AutomationModelRealmProxy.validateTable(AutomationModelRealmProxy.java:209)
                                                                     at io.realm.DefaultRealmModuleMediator.validateTable(DefaultRealmModuleMediator.java:69)
                                                                     at io.realm.Realm.initializeRealm(Realm.java:293)
                                                                     at io.realm.Realm.createAndValidate(Realm.java:261)
                                                                     at io.realm.Realm.createInstance(Realm.java:240)
                                                                     at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:114)
                                                                     at io.realm.Realm.getDefaultInstance(Realm.java:181)
                                                                     at com.github.openwebnet.database.DatabaseRealm.getRealmInstance(DatabaseRealm.java:51)
                                                                     at com.github.openwebnet.database.DatabaseRealm.query(DatabaseRealm.java:79)
                                                                     at com.github.openwebnet.database.DatabaseRealm.findSortedAscending(DatabaseRealm.java:87)
                                                                     at com.github.openwebnet.repository.impl.EnvironmentRepositoryImpl.lambda$findAll$125(EnvironmentRepositoryImpl.java:96)
                                                                     at com.github.openwebnet.repository.impl.EnvironmentRepositoryImpl.access$lambda$4(EnvironmentRepositoryImpl.java)
                                                                     at com.github.openwebnet.repository.impl.EnvironmentRepositoryImpl$$Lambda$5.call(Unknown Source)
                                                                     at rx.Observable.subscribe(Observable.java:8191)
                                                                     at rx.Observable.subscribe(Observable.java:8158)
                                                                     at rx.Observable.subscribe(Observable.java:7962)
                                                                     at com.github.openwebnet.view.MainActivity.reloadMenu(MainActivity.java:164)
                                                                     at com.github.openwebnet.view.MainActivity.onPrepareOptionsMenu(MainActivity.java:157)
                                                                     at android.app.Activity.onPreparePanel(Activity.java:2864)
                                                                     at android.support.v4.app.FragmentActivity.onPrepareOptionsPanel(FragmentActivity.java:487)
                                                                     at android.support.v4.app.FragmentActivity.onPreparePanel(FragmentActivity.java:476)
                                                                     at android.support.v7.internal.view.WindowCallbackWrapper.onPreparePanel(WindowCallbackWrapper.java:90)
                                                                     at android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.onPreparePanel(AppCompatDelegateImplBase.java:270)
                                                                     at android.support.v7.internal.view.WindowCallbackWrapper.onPreparePanel(WindowCallbackWrapper.java:90)
                                                                     at android.support.v7.internal.app.ToolbarActionBar$ToolbarCallbackWrapper.onPreparePanel(ToolbarActionBar.java:555)
                                                                     at android.support.v7.internal.app.ToolbarActionBar.populateOptionsMenu(ToolbarActionBar.java:448)
                                                                     at android.support.v7.internal.app.ToolbarActionBar$1.run(ToolbarActionBar.java:65)
                                                                     at android.os.Handler.handleCallback(Handler.java:739)
                                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                     at android.os.Looper.loop(Looper.java:148)
                                                                     at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-01 07:14:01.123 4368-4368/com.github.openwebnet E/OpenWebNet: FIND_FAVOURITES-orderByName
                                                                 io.realm.exceptions.RealmMigrationNeededException: Field 'uuid' does support null values in the existing Realm file. Remove @Required or @PrimaryKey from field 'uuid' or migrate using io.realm.internal.Table.convertColumnToNotNullable().
                                                                     at io.realm.AutomationModelRealmProxy.validateTable(AutomationModelRealmProxy.java:209)
                                                                     at io.realm.DefaultRealmModuleMediator.validateTable(DefaultRealmModuleMediator.java:69)
                                                                     at io.realm.Realm.initializeRealm(Realm.java:293)
                                                                     at io.realm.Realm.createAndValidate(Realm.java:261)
                                                                     at io.realm.Realm.createInstance(Realm.java:240)
                                                                     at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:114)
                                                                     at io.realm.Realm.getDefaultInstance(Realm.java:181)
                                                                     at com.github.openwebnet.database.DatabaseRealm.getRealmInstance(DatabaseRealm.java:51)
                                                                     at com.github.openwebnet.database.DatabaseRealm.query(DatabaseRealm.java:79)
                                                                     at com.github.openwebnet.database.DatabaseRealm.findCopyWhere(DatabaseRealm.java:109)
                                                                     at com.github.openwebnet.repository.impl.DomoticRepositoryImpl.lambda$findFavourites$120(DomoticRepositoryImpl.java:43)
                                                                     at com.github.openwebnet.repository.impl.DomoticRepositoryImpl.access$lambda$1(DomoticRepositoryImpl.java)
                                                                     at com.github.openwebnet.repository.impl.DomoticRepositoryImpl$$Lambda$2.call(Unknown Source)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable.unsafeSubscribe(Observable.java:8098)
                                                                     at rx.internal.operators.OperatorZip$Zip.start(OperatorZip.java:209)
                                                                     at rx.internal.operators.OperatorZip$ZipSubscriber.onNext(OperatorZip.java:156)
                                                                     at rx.internal.operators.OperatorZip$ZipSubscriber.onNext(OperatorZip.java:122)
                                                                     at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:46)
                                                                     at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:35)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable.subscribe(Observable.java:8191)
                                                                     at rx.Observable.subscribe(Observable.java:8158)
                                                                     at rx.Observable.subscribe(Observable.java:7914)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.initCards(DeviceListFragment.java:163)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.onEvent(DeviceListFragment.java:143)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at de.greenrobot.event.EventBus.invokeSubscriber(EventBus.java:492)
                                                                     at de.greenrobot.event.EventBus.postToSubscription(EventBus.java:423)
                                                                     at de.greenrobot.event.EventBus.postSingleEventForEventType(EventBus.java:404)
                                                                     at de.greenrobot.event.EventBus.postSingleEvent(EventBus.java:377)
                                                                     at de.greenrobot.event.EventBus.post(EventBus.java:258)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.lambda$onResume$1(DeviceListFragment.java:109)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.access$lambda$1(DeviceListFragment.java)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment$$Lambda$2.run(Unknown Source)
                                                                     at android.os.Handler.handleCallback(Handler.java:739)
                                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                     at android.os.Looper.loop(Looper.java:148)
                                                                     at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-01 07:14:01.123 4368-4368/com.github.openwebnet E/OpenWebNet: ERROR initCards
                                                                 io.realm.exceptions.RealmMigrationNeededException: Field 'uuid' does support null values in the existing Realm file. Remove @Required or @PrimaryKey from field 'uuid' or migrate using io.realm.internal.Table.convertColumnToNotNullable().
                                                                     at io.realm.AutomationModelRealmProxy.validateTable(AutomationModelRealmProxy.java:209)
                                                                     at io.realm.DefaultRealmModuleMediator.validateTable(DefaultRealmModuleMediator.java:69)
                                                                     at io.realm.Realm.initializeRealm(Realm.java:293)
                                                                     at io.realm.Realm.createAndValidate(Realm.java:261)
                                                                     at io.realm.Realm.createInstance(Realm.java:240)
                                                                     at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:114)
                                                                     at io.realm.Realm.getDefaultInstance(Realm.java:181)
                                                                     at com.github.openwebnet.database.DatabaseRealm.getRealmInstance(DatabaseRealm.java:51)
                                                                     at com.github.openwebnet.database.DatabaseRealm.query(DatabaseRealm.java:79)
                                                                     at com.github.openwebnet.database.DatabaseRealm.findCopyWhere(DatabaseRealm.java:109)
                                                                     at com.github.openwebnet.repository.impl.DomoticRepositoryImpl.lambda$findFavourites$120(DomoticRepositoryImpl.java:43)
                                                                     at com.github.openwebnet.repository.impl.DomoticRepositoryImpl.access$lambda$1(DomoticRepositoryImpl.java)
                                                                     at com.github.openwebnet.repository.impl.DomoticRepositoryImpl$$Lambda$2.call(Unknown Source)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable.unsafeSubscribe(Observable.java:8098)
                                                                     at rx.internal.operators.OperatorZip$Zip.start(OperatorZip.java:209)
                                                                     at rx.internal.operators.OperatorZip$ZipSubscriber.onNext(OperatorZip.java:156)
                                                                     at rx.internal.operators.OperatorZip$ZipSubscriber.onNext(OperatorZip.java:122)
                                                                     at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:46)
                                                                     at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:35)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable$2.call(Observable.java:162)
                                                                     at rx.Observable$2.call(Observable.java:154)
                                                                     at rx.Observable.subscribe(Observable.java:8191)
                                                                     at rx.Observable.subscribe(Observable.java:8158)
                                                                     at rx.Observable.subscribe(Observable.java:7914)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.initCards(DeviceListFragment.java:163)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.onEvent(DeviceListFragment.java:143)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at de.greenrobot.event.EventBus.invokeSubscriber(EventBus.java:492)
                                                                     at de.greenrobot.event.EventBus.postToSubscription(EventBus.java:423)
                                                                     at de.greenrobot.event.EventBus.postSingleEventForEventType(EventBus.java:404)
                                                                     at de.greenrobot.event.EventBus.postSingleEvent(EventBus.java:377)
                                                                     at de.greenrobot.event.EventBus.post(EventBus.java:258)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.lambda$onResume$1(DeviceListFragment.java:109)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment.access$lambda$1(DeviceListFragment.java)
                                                                     at com.github.openwebnet.view.device.DeviceListFragment$$Lambda$2.run(Unknown Source)
                                                                     at android.os.Handler.handleCallback(Handler.java:739)
                                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                     at android.os.Looper.loop(Looper.java:148)
                                                                     at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-01 07:14:01.124 4368-4368/com.github.openwebnet E/EventBus: Could not dispatch event: class com.github.openwebnet.view.device.DeviceListFragment$UpdateDeviceListEvent to subscribing class class com.github.openwebnet.view.device.DeviceListFragment
                                                               rx.exceptions.OnErrorNotImplementedException: Field 'uuid' does support null values in the existing Realm file. Remove @Required or @PrimaryKey from field 'uuid' or migrate using io.realm.internal.Table.convertColumnToNotNullable().
                                                                   at rx.Observable$27.onError(Observable.java:7923)
                                                                   at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:159)
                                                                   at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:120)
                                                                   at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:71)
                                                                   at rx.internal.operators.OperatorZip$Zip$InnerSubscriber.onError(OperatorZip.java:320)
                                                                   at rx.internal.operators.OperatorSingle$ParentSubscriber.onError(OperatorSingle.java:139)
                                                                   at rx.internal.operators.OperatorTakeLastOne$ParentSubscriber.onError(OperatorTakeLastOne.java:164)
                                                                   at rx.internal.operators.OperatorScan$InitialProducer.checkTerminated(OperatorScan.java:214)
                                                                   at rx.internal.operators.OperatorScan$InitialProducer.emitLoop(OperatorScan.java:307)
                                                                   at rx.internal.operators.OperatorScan$InitialProducer.emit(OperatorScan.java:293)
                                                                   at rx.internal.operators.OperatorScan$InitialProducer.onError(OperatorScan.java:229)
                                                                   at rx.internal.operators.OperatorScan$3.onError(OperatorScan.java:151)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:240)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:776)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:537)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:526)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.onError(OperatorMerge.java:250)
                                                                   at rx.internal.operators.OperatorMap$1.onError(OperatorMap.java:48)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.reportError(OperatorMerge.java:240)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.checkTerminate(OperatorMerge.java:776)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:537)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:526)
                                                                   at rx.internal.operators.OperatorMerge$MergeSubscriber.onError(OperatorMerge.java:250)
                                                                   at rx.internal.operators.OperatorMap$1.onError(OperatorMap.java:48)
                                                                   at com.github.openwebnet.repository.impl.DomoticRepositoryImpl.lambda$findFavourites$120(DomoticRepositoryImpl.java:47)
                                                                   at com.github.openwebnet.repository.impl.DomoticRepositoryImpl.access$lambda$1(DomoticRepositoryImpl.java)
                                                                   at com.github.openwebnet.repository.impl.DomoticRepositoryImpl$$Lambda$2.call(Unknown Source)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable.unsafeSubscribe(Observable.java:8098)
                                                                   at rx.internal.operators.OperatorZip$Zip.start(OperatorZip.java:209)
                                                                   at rx.internal.operators.OperatorZip$ZipSubscriber.onNext(OperatorZip.java:156)
                                                                   at rx.internal.operators.OperatorZip$ZipSubscriber.onNext(OperatorZip.java:122)
                                                                   at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:46)
                                                                   at rx.internal.util.ScalarSynchronousObservable$1.call(ScalarSynchronousObservable.java:35)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                   at rx.Observable$2.call(Observable.java:162)
                                                                   at rx.Observable$2.call(Observable.java:154)
                                                                at rx.Observable.su
moreau-nicolas commented 8 years ago

Regarding the Mockito configuration: I had an error running the unit tests without the configuration, adding it solves the problem. That's all I know. :-/

I agree that the solution is not ideal though. You can reproduce the problem by removing the class and running the unit tests again.

I'll look at the stack trace a bit later.

niqdev commented 8 years ago

Ok thanks. Let me know about the stacktrace and if you are able to reproduce the issue!

niqdev commented 8 years ago

I will fix this error directly on development branch and at the same time I will upgrade realm to the latest version

niqdev commented 8 years ago

I've just released version 1.4.0 only for beta tester with this feature and the one of the light also if incomplete. Please enroll as beta tester with this link, I can't verify the Automation so I will not release this version in production until you give me a feedback that everything is working fine. The link should be available in the next hours. Thanks!

moreau-nicolas commented 8 years ago

I have enrolled for the beta program, I'll download & install it tomorrow and let you know if the build works properly.

PS: I saw the MigrationStrategy fix in a867ce6, nice work ! And sorry for the newbie mistake !

niqdev commented 8 years ago

I released version 1.4.1 for beta testing, so new update will be available soon. I need french translation for this please

PS: correct my english for play store comment if I do any mistake! Thanks!

moreau-nicolas commented 8 years ago

Here goes the translation :

  • Traduction en Français
  • Gestion des automatismes (volets)
  • Changements mineurs de style

I didn't see anything wrong with the English translations, but I'm not a native speaker so I might have missed something.

niqdev commented 8 years ago

:+1:

moreau-nicolas commented 8 years ago

I have tested the 1.4.1 from the development branch on my device and automation works as expected. :)

I didn't try from the Play store because I didn't want to lose my configuration.

niqdev commented 8 years ago

Ok thanks, I will release it in prod soon

niqdev commented 8 years ago

Could you please update this image in english for the play store? I would like to substitute one of the light card with automation. Sorry but for you is easier, cos I don't have any automation! Thanks

moreau-nicolas commented 8 years ago

Here it is:

screenshot_20160306-194413

Please let me know if you need more screen captures.