The place where random ideas get written down and lost in time.

2021-09-03 - End of Summer Project B3

Category DEV

Time to end the summer project with Bearing B3. Steps needed:

  • Publish it!
  • Check if I can update only the Installed version, without the “Instant” one.
  • I do realize the Installed-vs-Instant doesn't make a lot of sense in this case due to the preference storage for the Waypoints list. When updating, any waypoints created with the Instant one will be lost.

Either way I’m likely to remove the Instant version as it’s mostly pointless here. It’s only here as an exercise...


2021-08-28 - Train Motion: FatJar vs ClassPath?

Category DEV

In the Train-Motion project, I have a fat jar gradle rule to package all the dependencies in a single jar.

To make it work, I had to create a “configuration” in gradle:

configurations {

    runtimeCompile {

        canBeResolved = true

        canBeConsumed = true

    }

    compileClasspath.extendsFrom(runtimeCompile)

    runtimeClasspath.extendsFrom(runtimeCompile)

    testCompileClasspath.extendsFrom(runtimeCompile)

    testRuntimeClasspath.extendsFrom(runtimeCompile)

}

Then I use this configuration to include the dependencies:

dependencies {

    runtimeCompile project(":LibUtilsJava")

    runtimeCompile "commons-cli:commons-cli:1.4"

    runtimeCompile "org.bytedeco:javacv-platform:1.5.3"

    runtimeCompile "org.bytedeco:javacpp-platform:1.5.3"

    runtimeCompile "uk.co.caprica:vlcj:4.7.1"

    runtimeCompile "com.fasterxml.jackson.core:jackson-databind:2.10.2"

    runtimeCompile "com.squareup.okhttp3:okhttp:3.10.0"

    runtimeCompile "org.eclipse.jetty:jetty-server:9.4.29.v20200521"

    runtimeCompile "com.google.dagger:dagger:2.28"

    runtimeCompile  "com.google.auto.factory:auto-factory:1.0.1"

}

And finally a fatJar task collects these specific dependencies and packages them together:

task fatJar(type: Jar) {

    manifest.from jar.manifest

    classifier = "all"

    from {

        configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) }

    } {

        exclude "META-INF/*.SF"

        exclude "META-INF/*.DSA"

        exclude "META-INF/*.RSA"

    }

    with jar

}

Note that “runtimeCompile” is a superset of the “compile” configuration, and the artifacts can be found using configurations.compileClasspath.

That’s neat to create the needed single JAR. That jar is ~760 MB with all the OpenCV deps. And it takes an interminable 4 minutes to create the jar itself.

So now the question is whether I can avoid that. I don’t need to distribute the jar, so I'd be fine with crafting a specific command line with the needed classpath. Or even having a “gradle run” task that does not need the fat jar first.


2021-08-18 - Bearing B3 Features

Category DEV

Now that we have a basic “marked locations” list in B3, it’s time to review the UI and adjust.

The goal was to do it in Kotlin, and that’s been done.

One issue was the “Marked Locations” wording, which seems problematic. Isn’t there something better… “waypoints” seem like a better name.

So let’s do a few changes:

  • Vocabulary:
    • A “Location” is just a raw GPS location coordinate (latitude + longitude).
    • A “Waypoint” is a location coordinate combined with a name.
  • Screen “Marked Locations” ⇒ “Waypoints”
    • “Marked Location” ⇒ “Selected Waypoint”
    • “Location N” ⇒ “Waypoint N”
    • Rename class Mark to Waypoint / Waypoints / WaypointsAdapter.
  • Screen “Compass”
    • “Marked Location” ⇒ “Target Location”
      • (that should make it more obvious it’s the target of the bearing)
    • Menu Recall / Edit ⇒ keep as-is for now.

We’ll keep the wording as “Location” (Target vs GPS) in the Compass screen.


2021-08-11 - Android Testing : AndroidX “AndroidJUnit4” vs Robolectric

Category DEV

I feel like a case of deja vu so I need to write this down.

  • Robolectric: simulating an Android runtime working on top of the JVM, local dev machine. No emulator needed.
    • Used to be simple and straightforward. Since Robolectric 4 and recent android gradle updates, some things have been deprecated / changed making it harder to use.
  • AndroidX runner “AndroidJUnitRunner” tests which go in androidTest folder: run on device or emulator, and are essentially the modern version of the instrumentation tests.
  • AndroidX runner “AndroidJUnit4” tests which go in androidTest folder: run on device or emulator too ⇒ the test folder name indicates which build rule is used and where the test runs.
  • AndroidX runner “MockitoJUnitRunner” tests which go in the test folder: run on JVM.
    • This is provided by mockito-core and is basically a JUnit runner that also happens to auto-init all the @Mock instances. ⇒ Just a convenience over the usual Mock rule, no relation to Android framework.
    • How much of the Android framework can be used with that? ⇒ none
  • Robolectric with AndroidX tests:

What I have done for Cab v2:

  • Build.gradle > defaultConfig > testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  • ServersActivityTest:
    • @RunWith(AndroidJUnit4.class)
      @Config(application = TestMainApp.class)
      ApplicationProvider.getApplicationContext()
      ActivityScenario.launch(MainActivity.class)
  • The cabv2 TestMainApp derives from the LegacyMainApp and replaces the IAppComponent by the ITestAppComponent for testing. That’s how test modules are injected in the app.

Since updating B3, I was getting errors:

  • “robolectric RuntimeException Method not mocked”
  • They are “solved” by adding this to app gradle:
    • testOptions > unitTests >  returnDefaultValues = true
  • Which in turn creates another error: “java.lang.ClassNotFoundException: android.content.res.ApkAssets”
  • Real solution: following https://github.com/robolectric/robolectric/issues/4740
    • The dumb solution is to remove the m2 robolectric cache so that it gets downloaded again.


2021-08-08 - Gradle Wrapper + Maven Repo Offline caching

Category DEV

https://softwareengineering.stackexchange.com/questions/331817/self-contained-projects-gradle-maven-dependencies-offline

This explains:

  • How to use an offline version of the Gradle wrapper.
  • How to use an offline version of a project’s Maven repo dependencies (cached once).


2021-08-05 - Summer Project: Bearing + Kotlin

Category DEV

Kotlin / rig4k is a good potential idea but really a project based around GDoc downloads & APIs sounds like a painful thing to do in PA. It requires internet connection (duh). But also GDoc APIs are notorious to change each time I look at them, requiring even more research -- that is there’s the issue that I’d have to learn the “idiomatic kotlin” and the “idiomatic gdoc API” at the same time.

So instead, what about Bearing? It could be a good Kotlin candidate:

  • No new API learning curve. The usual Android stuff, just done as Kotlin.
  • Can focus on Kotlin syntax & such.
  • One option would be to rewrite the whole app in Kotlin, however… what’s the benefit?
  • Can just mix with the current version and add new stuff in Kotlin.

That is the addition would be a new fragment or activity for a mark list management, which is neatly self-contained.


2021-08-05 - Looking back at Bearing B3

Category DEV

When I (re)created Bearing B3, I tried a few things:

  • The “new” ABB (Android Bundle) mode.
    • Not a big fan but this is the way to go since Play will eventually make AAB mandatory in 2021 or 2022.
    • It was a good test and useful, and I shall keep it that way for distrib.
  • The new “instant vs installed” modes.
    • That was good learning to realize that instant creates some limitations, e.g. can’t bundle analytics stats with it.
    • Other than that, it makes the build config a bit more complicated by having 2 variants.
    • Overall it doesn’t bring much in terms of visibility. E.g. how many apps are installed vs run as instant?
  • FirebaseAnalytics instead of GA.
    • Same difference?
    • Need to constantly update the library… it’s obsolete again IIRC.

Work suggestions:

  • Remove the “instant” variant. Only keep the installed one.
    • What about google play? Can I remove the instant version there too?
    • ⇒ update the “installed” version first and check if the “instant” can be removed from Play. If it does, then cleanup the “instant” build script + code.
  • Check updating of the Firebase library.
    • ⇒ That’s enough update needed to create the new installed variant.


2021-08-02 - Summer Project: Bearing

Category DEV

Guess what… I’m in PA and I already want to add a couple features to Bearing:

  • Create a marked location list + auto save/load.
  • When marking a location:
    • Add it to the list. Names a “Location 1…” + auto-inc (use list length).
      • TBD later ⇒ dialog to edit name before adding it + cancel.
      • But to get started, generate name automatically.
    • Display name in small font below marked location.
  • Add a little “3-dot menu” on the “Marked Loc” line. Popup a menu:
    • Recall / Edit…         ⇒ goes to marked loc fragment (see below).                  [done]
    • Share…                 ⇒ share location as text/etc                                        [done]
    • V2: Rename…         ⇒ dialog with one text edit field.
    • V2: Save                 ⇒ enabled/visible if marked loc is not in current list (e.g. upgrade or deleted).
  • Share bearing (as text, to google maps).                                                        [done]
  • Marked locs fragment:
    • Reuse the current pattern (fragments in a single activity).                        [done]
    • Simple text list. Select an item : [Delete] / [Recall] / [Rename (v2)].        [done]
    • List items: GPS loc + date/time + name on 2nd line.        [done]
      • V1: Not listing the time
    • Delete with confirmation ⇒ does not remove current marked loc.                 [done]
    • Recall: honor the pref setting “ask before override marked loc”.                [done]
      • Recall would erase the current mark loc,
      • Then go directly to the compass view.
    • V2: Share selected mark.
    • V2: Export all marks as text.
    • V2 or +: reorder, rename.
  • Consider renaming “marked locations” to “waypoints”?
  • Split screen:
    • Bottom is list view
    • V2: top is map view of selected list item.
    • V2: top is detail info for item. Name edit field to rename. Trash icon for delete with confirmation. Eye or compass icon to make it the mark in compass.


2021-02-17 - ESP32 Learning: MQTT

Category DEV

This is something I need to look into at some point: MQTT to send messages between ESP32 nodes on a local network.

There’s a group (MQTT4MR) that uses that to control sensors via JMRI (instead of C/MRI over RS485 wires).

MQTT is also used typically with LoRa and such for larger distance networks, I believe using brokers/hubs. However that’s not really my first usage.

https://learn.adafruit.com/mqtt-adafruit-io-and-you?view=all MQTT very high overview:

  • Designed for sensors … small payloads, infrequent data, not heavy streams.
    • Which is why it works well with LoRa (bandwidth vs distance, pick one).
  • It’s a N-to-1 design: one server somewhere, multiple clients.
  • Either one device acts as a server, or a “broker” app/script runs on a network computer.
    • JMRI uses the latter design for obvious reasons.
    • There are internet-wide brokers like adafruit.io
  • To connect to a broker, need server/ip, port, username, and a key.
  • The whole concept is a pub-sub:
    • Devices publish to the server.
    • Devices subscribe to the server.
  • Subscribers need to send a ping (e.g. every 5 minutes).
    • Failing to ping disconnects the device.
  • Adafruit_MQTT is such a lib for arduino.
    • They warn it’s single-duplex: a subscription message would be lost if the device is transmitting (ping or publication) at the same time.
  • Quality-of-service:
    • QOS 0 = send publication message without checking they arrived.
    • QOS 1 = send publication message with an OK / ack.
  • A “will” is a message defined such that the broker sends it when the client disconnects.


2021-02-07 - Conductor2… Kotlin vs Groovy again

Category DEV

It’s been 2 years now that I started the rewrite of Conductor 2. Back then I chose Groovy, after trying Kotlin and deciding it wasn’t mature enough. In between, Kotlin usage has expanded a lot, so time to revisit.

(N.D.L.R.: the goal of the Conductor 2 project is to replace the custom language from Conductor 1 by a new DSL based on top of Groovy, or Kotlin. That would allow the script to have more flexibility.)

Overall Conductor2 with Groovy would work. Although the engine isn’t 100% operational, I rewrote most of the main automation script using Groovy and I updated it to a few new concepts that I miss in my current custom language.

The Conductor 2 design doc has more details on the new syntax.

Through the implementation, I evolved the syntax.

In conductor 1, we have basically a “global” namespace of “conditions --> actions”.

These can be expressed in the Groovy script using:

On { closure expression return a boolean } --> { actions block }

However I later rewrote the script to be more oriented for each route / block.

A route is defined as a sequence of blocks that must be traversed, and there are actions for each block. This avoids the soup of global state variables that must be maintained in Conductor 1 to achieve the same thing (e.g. “passenger train on this block going forward”). The new syntax looks like this:

Name = route {

        Route = [

                BlockNumber.forward {

                        onStart { actions }

                        onEnter { actions } then_after delay { actions }

        after delay { actions } then_after delay { actions }

} ] }

This scheme basically encodes most of the complexity in Conductor 1’s script, which is using timers and global state to limit actions to certain routes/blocks/directions.

Click here to continue reading...


 Generated on 2025-02-20 by Rig4j 0.1-Exp-f2c0035