Skip to content

Commit

Permalink
electric meter and trigonometry
Browse files Browse the repository at this point in the history
  • Loading branch information
djnzx committed Aug 24, 2024
1 parent 529cbce commit 6db79cb
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 22 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ lazy val ce3 = (project in file("ce3"))
"io.kubernetes" % "client-java-api" % "20.0.1",
"io.kubernetes" % "client-java" % "20.0.1",
"jakarta.mail" % "jakarta.mail-api" % "2.1.3",
"io.scalaland" %% "chimney" % "1.1.0",
"io.scalaland" %% "chimney" % "1.4.0",
"org.tpolecat" %% "skunk-core" % "0.6.4",
"io.7mind.izumi" %% "logstage-core" % "1.2.10",
"org.tpolecat" %% "doobie-core" % "1.0.0-RC2",
Expand Down
69 changes: 48 additions & 21 deletions ce3/src/main/scala/el_meter/Sandbox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,87 @@ package el_meter

import cats.effect.IO
import cats.effect.unsafe.implicits.global
import cats.implicits.catsSyntaxApplicativeId
import org.http4s.Header
import org.http4s.MediaType
import cats.implicits._
import io.scalaland.chimney.Transformer
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import org.http4s.Method
import org.http4s.Request
import org.http4s.Status.BadRequest
import org.http4s.Status.ClientError
import org.http4s.Status.Successful
import org.http4s.Status.TooManyRequests
import org.http4s.blaze.client.BlazeClientBuilder
import org.http4s.circe.CirceEntityCodec.circeEntityDecoder
import org.http4s.implicits.http4sLiteralsSyntax
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import org.typelevel.ci.CIStringSyntax
import scala.concurrent.duration.DurationInt

object Http {

private def mkHttpClient =
def mkHttpClient =
BlazeClientBuilder[IO].resource

private val url = uri"http://192.168.7.38?page=getdata&devid=1828726629&devpass=6543"
import org.http4s.headers._
val rq = Request[IO](Method.GET, url)
.withHeaders(
`Accept`(MediaType.application.json),
Header.Raw(ci"User-Agent", "IntelliJ HTTP Client/IntelliJ IDEA 2024.2"),
Header.Raw(ci"Accept-Encoding", "br, deflate, gzip, x-gzip"),
// Header.Raw(ci"Accept", "*/*"),
Header.Raw(ci"content-length", "0"),
)

import model._

def getData = mkHttpClient
.flatMap(_.run(rq))
.use {
// case x => x.body.compile.count.flatMap(x => IO(pprint.log(x))) >>
case Successful(rs) => rs.attemptAs[RawResponse].value
.flatMap {
case Right(x) => x.pure[IO]
case Left(x) => IO(pprint.log(x))
}
case x => IO(pprint.log(x)) >> IO.raiseError(new RuntimeException("wrong response"))
case Successful(rs) => rs.as[RawResponse].map(_.some)
case ClientError(rs) if rs.status == TooManyRequests => IO(None)
case x => IO(pprint.log(x)) >> IO.raiseError(new RuntimeException("wrong response"))
}

}

class SandboxSpec extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {

import Http._
import io.scalaland.chimney.inlined._
import model._
// import io.scalaland.chimney.dsl._

test("round") {
pprint.log(round1(1.23456))
}

test("instant") {
val raw = "1724506617"
val ldt = LocalDateTime.ofInstant(
Instant.ofEpochSecond(raw.toInt),
ZoneOffset.ofHours(3)
)
pprint.log(ldt)

test("1") {
}

test("one value") {
getData
.map(_.getOrElse(???))
.map(_.into[DataLine].transform)
.map(_.into[DataLineWattOnlyDetailed].transform)
.flatMap(x => IO(pprint.log(x)))
.unsafeRunSync()
}

test("streamed") {
fs2.Stream
.awakeEvery[IO](5000.millis)
.evalMap(_ => getData)
.unNone
.map(_.into[DataLine].transform)
.map(_.into[DataLineWattOnlyDetailed].transform)
.map(_.into[DataLineWattOnlyShort].transform)
.evalTap(x => IO(pprint.log(x)))
.compile
.drain
.unsafeRunSync()
}

}
79 changes: 79 additions & 0 deletions ce3/src/main/scala/el_meter/model.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package el_meter

import io.circe.generic.AutoDerivation
import io.scalaland.chimney.Transformer
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset

object model {

Expand Down Expand Up @@ -60,4 +64,79 @@ object model {
)
object RawResponse extends AutoDerivation

case class Item(
name: String,
unit: String,
value: Double
)

case class Data(
V1: Item,
A1: Item,
W1: Item,
PF1: Item,
//
V2: Item,
A2: Item,
W2: Item,
PF2: Item,
//
V3: Item,
A3: Item,
W3: Item,
PF3: Item,
//
A: Item,
W: Item,
)

case class DataLine(
time: LocalDateTime,
data: Data
)

case class DataWattOnly(
W1: Item,
W2: Item,
W3: Item,
W: Item,
)
case class DataLineWattOnlyDetailed(
time: LocalDateTime,
data: DataWattOnly
)

case class DataLineWattOnlyShort(
time: LocalDateTime,
W1: Double,
W2: Double,
W3: Double,
W: Double,
)

def round1(x: Double): Double = (x * 10).round.toDouble / 10

implicit val tr0: Transformer[String, LocalDateTime] = (src: String) =>
LocalDateTime.ofInstant(
Instant.ofEpochSecond(src.toInt),
ZoneOffset.ofHours(3)
)

implicit val tr1: Transformer[RawItem, Item] = Transformer.define[RawItem, Item]
.withFieldComputed(_.value, r => round1(r.value.toDouble))
.buildTransformer

implicit val tr2: Transformer[RawData, Data] = Transformer.derive[RawData, Data]

implicit val tr3: Transformer[Data, DataWattOnly] = Transformer.derive[Data, DataWattOnly]

implicit val tr4: Transformer[DataLine, DataLineWattOnlyDetailed] = Transformer.derive[DataLine, DataLineWattOnlyDetailed]

implicit val tr6 = Transformer.define[DataLineWattOnlyDetailed, DataLineWattOnlyShort]
.withFieldComputed(_.W1, _.data.W1.value)
.withFieldComputed(_.W2, _.data.W2.value)
.withFieldComputed(_.W3, _.data.W3.value)
.withFieldComputed(_.W, _.data.W.value)
.buildTransformer

}
69 changes: 69 additions & 0 deletions ce3/src/main/scala/trigonometry/Trigonometry.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package trigonometry

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks

class Trigonometry extends AnyFunSuite with Matchers with ScalaCheckPropertyChecks {

import scala.math._

def round(x: Double, nDigits: Int): Double = {
val k = pow(10, nDigits)
(x * k).round.toDouble / k
}
def round1(x: Double): Double = round(x, 1)
def round2(x: Double): Double = round(x, 2)

test("degree => radians") {
Seq(
0, // 0
45, // Pi/4
90, // Pi/2
180, // Pi
360, // 2*Pi
)
.map(_.toRadians)
.foreach(x => pprint.log(x))
}

test("radians => degree") {
Seq(
0, // 0
Pi / 4, // 45
Pi / 2, // 90
Pi, // 180
2 * Pi, // 360
)
.map(_.toDegrees)
.foreach(x => pprint.log(x))
}

test("sin, cos, tan requires radians") {
Seq(
0,
45, // 1/sqrt(2)
90,
180,
270,
360,
)
.map(x => (x, x.toRadians))
.map { case x @ (_, r) => x -> (sin(r), cos(r), tan(r)) }
.foreach(x => pprint.log(x))
}

test("asin, acos return radians") {
Seq(
1.0, // 0
0.9, // 25
0.8, // 37
0.7, // 45
0.5, // 60
)
.map(x => acos(x))
.map(_.toDegrees)
.foreach(x => pprint.log(x))
}

}
6 changes: 6 additions & 0 deletions ce3/src/main/scala/trigonometry/triginometry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
1. $$Radians = Degrees \times {π \over 180}$$
2. $$Degrees = Radians \times {180 \over π}$$
3. $$1^{\circ} = {π \over 180} radians = 0.0174533 radians$$
4. $$90^{\circ} = {π \over 2} radians = 1.5708 radians$$
5. $$180^{\circ} = π radians = 3.1416 radians$$
6. $$360^{\circ} = 2 \times π radians = 3.1416 radians$$

0 comments on commit 6db79cb

Please sign in to comment.